Skip to content

Commit

Permalink
Merge pull request #897 from bcgov/dev
Browse files Browse the repository at this point in the history
gwa cli v2
  • Loading branch information
ikethecoder committed Sep 8, 2023
2 parents 9301fd1 + b7a2572 commit a09f38c
Show file tree
Hide file tree
Showing 40 changed files with 660 additions and 216 deletions.
23 changes: 9 additions & 14 deletions src/api-openapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@ class ApiOpenapiApp {

RegisterRoutes(app);

// RFC 8631 service-desc link relation
// https://datatracker.ietf.org/doc/html/rfc8631
app.get('/ds/api', (req, res) => {
res.setHeader('Link', '</ds/api/openapi.yaml>; rel="service-desc"');
res.status(204).end();
});

app.get('/ds/api/openapi.yaml', (req, res) => {
res.setHeader('Content-Type', 'application/yaml');
res.send(spec);
Expand All @@ -54,14 +47,9 @@ class ApiOpenapiApp {
*/
specObject.components.securitySchemes.jwt.flows.clientCredentials.tokenUrl = `${process.env.OIDC_ISSUER}/protocol/openid-connect/token`;

RegisterRoutes(app);
specObject.components.securitySchemes.openid.openIdConnectUrl = `${process.env.OIDC_ISSUER}/.well-known/openid-configuration`;

// RFC 8631 service-desc link relation
// https://datatracker.ietf.org/doc/html/rfc8631
app.get('/ds/api/v2', (req, res) => {
res.setHeader('Link', '</ds/api/openapi.yaml>; rel="service-desc"');
res.status(204).end();
});
RegisterRoutes(app);

app.get('/ds/api/v2/openapi.yaml', (req, res) => {
res.setHeader('Content-Type', 'application/yaml');
Expand All @@ -86,6 +74,13 @@ class ApiOpenapiApp {
this.prepareV2(app);
this.prepareV1(app);

// RFC 8631 service-desc link relation
// https://datatracker.ietf.org/doc/html/rfc8631
app.get('/ds/api', (req, res) => {
res.setHeader('Link', '</ds/api/v2/openapi.yaml>; rel="service-desc"');
res.status(204).end();
});

app.use(function errorHandler(err, req, res, next) {
if (err instanceof UnauthorizedError) {
return res.status(err.status).json({
Expand Down
52 changes: 29 additions & 23 deletions src/api-proxy.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

const express = require('express');
const pathModule = require('path');

Expand All @@ -11,31 +10,38 @@ class ApiProxyApp {

prepareMiddleware({ keystone }) {
const app = express();

const apiProxy = createProxyMiddleware({
target: this._gwaApiUrl,
changeOrigin: true,
pathRewrite: { '^/gw/api/': '/v2/' },
onProxyReq: (proxyReq, req) => {
// console.log(req.headers)
// proxyReq.removeHeader("cookie");
proxyReq.removeHeader("cookie");
proxyReq.setHeader('Accept', 'application/json')
proxyReq.setHeader('Authorization', `Bearer ${req.header('x-forwarded-access-token')}`) },
onError:(err, req, res, target) => {
console.log(err)
res.writeHead(400, {
'Content-Type': 'text/plain',
});
res.end('error reaching api');
}
})
app.all(/^\/gw\/api\//, apiProxy)

const apiProxy = createProxyMiddleware({
target: this._gwaApiUrl,
changeOrigin: true,
logLevel: 'debug',
pathRewrite: { '^/gw/api/': '/v2/' },
onProxyReq: (proxyReq, req) => {
//console.log(req.headers)
// proxyReq.removeHeader("cookie");
proxyReq.removeHeader('cookie');
proxyReq.setHeader('Accept', 'application/json');
proxyReq.setHeader(
'Authorization',
'authorization' in req.headers
? req.header('authorization')
: `Bearer ${req.header('x-forwarded-access-token')}`
);
},
onError: (err, req, res, target) => {
console.log(err);
res.writeHead(400, {
'Content-Type': 'text/plain',
});
res.end('error reaching api');
},
});
app.all(/^\/gw\/api\//, apiProxy);

return app;
}
}

module.exports = {
ApiProxyApp,
};
ApiProxyApp,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

mutation CreateNamespace($name: String!) {
createNamespace(name: $name) {
id
name
}
}
4 changes: 2 additions & 2 deletions src/batch/data-rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const metadata = {
Namespace: {
query: 'allNamespaces',
refKey: 'extRefId',
sync: ['name'],
sync: ['name', 'displayName'],
transformations: {
// members: {
// name: 'connectExclusiveList',
Expand Down Expand Up @@ -474,7 +474,7 @@ const metadata = {
resourceScopes: { name: 'toStringDefaultArray' },
clientRoles: { name: 'toStringDefaultArray' },
clientMappers: { name: 'toStringDefaultArray' },
environmentDetails: { name: 'toString' },
environmentDetails: { name: 'toStringDefaultArray' },
inheritFrom: {
name: 'connectOne',
list: 'allSharedIdPs',
Expand Down
7 changes: 6 additions & 1 deletion src/batch/feed-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,14 @@ export const syncRecords = async function (
}
if (Object.keys(data).length === 0) {
logger.debug('[%s] [%s] no update', entity, localRecord.id);
const firstChildResult = childResults
.filter((r) => r.result != 'no-change')
.pop();
return {
status: 200,
result: 'no-change',
result: firstChildResult
? firstChildResult.result + '-child'
: 'no-change',
id: localRecord['id'],
childResults,
ownedBy:
Expand Down
4 changes: 4 additions & 0 deletions src/batch/transformations/toStringDefaultArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export function toStringDefaultArray(
inputData: any,
key: string
) {
// if new and not passed, then set an empty array as a default
if (inputData[key] == null && currentData == null) {
return '[]';
}
return inputData[key] == null ||
(currentData != null && currentData[key] === stringify(inputData[key]))
? null
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/ioc/keystoneInjector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ export class KeystoneService {
public createContext(request: any, skipAccessControl: boolean = false): any {
const _scopes = scopes(request.user.scope);

const identityProvider = request.user.identity_provider;

const identity = {
id: null,
name: resolveName(request.user),
username: resolveUsername(request.user),
namespace: request.params.ns,
roles: JSON.stringify(scopesToRoles(null, _scopes)),
roles: JSON.stringify(scopesToRoles(identityProvider, _scopes)),
scopes: _scopes,
userId: null,
} as any;
Expand Down
14 changes: 14 additions & 0 deletions src/controllers/v2/GatewayController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Security,
Body,
Tags,
FormField,
UploadedFile,
} from 'tsoa';
import { KeystoneService } from '../ioc/keystoneInjector';
import { inject, injectable } from 'tsyringe';
Expand All @@ -20,6 +22,7 @@ import {
removeKeys,
} from '../../batch/feed-worker';
import { GatewayRoute } from './types';
import { PublishResult } from './types-extra';

@injectable()
@Route('/namespaces/{ns}/gateway')
Expand All @@ -31,6 +34,17 @@ export class GatewayController extends Controller {
this.keystone = _keystone;
}

@Put()
@OperationId('publish-gateway-config')
@Security('jwt', ['Gateway.Config'])
public async put(
@FormField() dryRun: boolean,
@UploadedFile() configFile: Express.Multer.File
): Promise<PublishResult> {
// stub - gwa-api implements this
return { error: 'Stub - not implemented' };
}

/**
* Get a summary of your Gateway Services
* > `Required Scope:` Namespace.Manage
Expand Down
51 changes: 49 additions & 2 deletions src/controllers/v2/NamespaceController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {
Tags,
Delete,
Query,
Post,
Body,
} from 'tsoa';
import { ValidateError, FieldErrors } from 'tsoa';
import { KeystoneService } from '../ioc/keystoneInjector';
import { inject, injectable } from 'tsyringe';
import { gql } from 'graphql-request';
import { WorkbookService } from '../../services/report/workbook.service';
import { Namespace } from '../../services/keystone/types';
import { Namespace, NamespaceInput } from '../../services/keystone/types';

import { Readable } from 'stream';
import {
Expand All @@ -33,6 +35,7 @@ import { Activity } from './types';
import { getActivity } from '../../services/keystone/activity';
import { transformActivity } from '../../services/workflow';
import { ActivityDetail } from './types-extra';

const logger = Logger('controllers.Namespace');

/**
Expand Down Expand Up @@ -107,7 +110,7 @@ export class NamespaceController extends Controller {
query: list,
});
logger.debug('Result %j', result);
return result.data.allNamespaces.map((ns: Namespace) => ns.name);
return result.data.allNamespaces.map((ns: Namespace) => ns.name).sort();
}

/**
Expand Down Expand Up @@ -136,6 +139,40 @@ export class NamespaceController extends Controller {
return result.data.namespace;
}

/**
* Create a namespace
*
* @summary Create Namespace
* @param ns
* @param request
* @returns
*/
@Post()
@OperationId('create-namespace')
@Security('jwt', [])
public async create(
@Request() request: any,
@Body() vars: NamespaceInput
): Promise<Namespace> {
const result = await this.keystone.executeGraphQL({
context: this.keystone.createContext(request),
query: createNS,
variables: vars,
});
logger.debug('Result %j', result);
if (result.errors) {
const errors: FieldErrors = {};
result.errors.forEach((err: any, ind: number) => {
errors[`d${ind}`] = { message: err.message };
});
throw new ValidateError(errors, 'Unable to create namespace');
}
return {
name: result.data.createNamespace.name,
displayName: result.data.createNamespace.displayName,
};
}

/**
* Delete the namespace
* > `Required Scope:` Namespace.Manage
Expand Down Expand Up @@ -214,6 +251,7 @@ const item = gql`
query Namespace($ns: String!) {
namespace(ns: $ns) {
name
displayName
scopes {
name
}
Expand All @@ -234,3 +272,12 @@ const deleteNS = gql`
forceDeleteNamespace(namespace: $ns, force: $force)
}
`;

const createNS = gql`
mutation CreateNamespace($name: String, $displayName: String) {
createNamespace(name: $name, displayName: $displayName) {
name
displayName
}
}
`;
Loading

0 comments on commit a09f38c

Please sign in to comment.