Skip to content

Commit

Permalink
feat: allows creation of PATs for other users (#2718)
Browse files Browse the repository at this point in the history
https://linear.app/unleash/issue/2-530/api-allow-creation-of-pats-for-other-users


![image](https://user-images.githubusercontent.com/14320932/208720680-5d5ccee7-1972-4f5b-8024-3a69d50a571f.png)

Adds and takes into account the following permissions:
 - **READ_USER_PAT**;
 - **CREATE_USER_PAT**;
 - **DELETE_USER_PAT**;
 
 API only, will make some exploration on UI soon.

Co-authored-by: Gastón Fournier <gaston@getunleash.ai>
  • Loading branch information
nunogois and Gastón Fournier committed Jan 2, 2023
1 parent aab809c commit 88004a6
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 8 deletions.
Expand Up @@ -36,3 +36,6 @@ export const DELETE_SEGMENT = 'DELETE_SEGMENT';
export const APPLY_CHANGE_REQUEST = 'APPLY_CHANGE_REQUEST';
export const APPROVE_CHANGE_REQUEST = 'APPROVE_CHANGE_REQUEST';
export const SKIP_CHANGE_REQUEST = 'SKIP_CHANGE_REQUEST';
export const READ_USER_PAT = 'READ_USER_PAT';
export const CREATE_USER_PAT = 'CREATE_USER_PAT';
export const DELETE_USER_PAT = 'DELETE_USER_PAT';
2 changes: 2 additions & 0 deletions src/lib/__snapshots__/create-config.test.ts.snap
Expand Up @@ -80,6 +80,7 @@ exports[`should create default config 1`] = `
"networkView": false,
"proxyReturnAllToggles": false,
"responseTimeWithAppName": false,
"serviceAccounts": false,
"variantsPerEnvironment": false,
},
},
Expand All @@ -98,6 +99,7 @@ exports[`should create default config 1`] = `
"networkView": false,
"proxyReturnAllToggles": false,
"responseTimeWithAppName": false,
"serviceAccounts": false,
"variantsPerEnvironment": false,
},
"externalResolver": {
Expand Down
8 changes: 6 additions & 2 deletions src/lib/routes/admin-api/user/pat.ts
Expand Up @@ -78,7 +78,11 @@ export default class PatController extends Controller {

async createPat(req: IAuthRequest, res: Response): Promise<void> {
const pat = req.body;
const createdPat = await this.patService.createPat(pat, req.user);
const createdPat = await this.patService.createPat(
pat,
req.user.id,
req.user,
);
this.openApiService.respondWithValidation(
201,
res,
Expand All @@ -88,7 +92,7 @@ export default class PatController extends Controller {
}

async getPats(req: IAuthRequest, res: Response<PatSchema>): Promise<void> {
const pats = await this.patService.getAll(req.user);
const pats = await this.patService.getAll(req.user.id);
this.openApiService.respondWithValidation(200, res, patsSchema.$id, {
pats: serializeDates(pats),
});
Expand Down
16 changes: 10 additions & 6 deletions src/lib/services/pat-service.ts
Expand Up @@ -33,24 +33,28 @@ export default class PatService {
this.eventStore = eventStore;
}

async createPat(pat: IPat, user: User): Promise<IPat> {
await this.validatePat(pat, user.id);
async createPat(
pat: IPat,
forUserId: number,
creator: User,
): Promise<IPat> {
await this.validatePat(pat, forUserId);
pat.secret = this.generateSecretKey();
pat.userId = user.id;
pat.userId = forUserId;
const newPat = await this.patStore.create(pat);

pat.secret = '***';
await this.eventStore.store({
type: PAT_CREATED,
createdBy: user.email || user.username,
createdBy: creator.email || creator.username,
data: pat,
});

return newPat;
}

async getAll(user: User): Promise<IPat[]> {
return this.patStore.getAllByUser(user.id);
async getAll(userId: number): Promise<IPat[]> {
return this.patStore.getAllByUser(userId);
}

async deletePat(id: number, userId: number): Promise<void> {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/types/experimental.ts
Expand Up @@ -51,6 +51,10 @@ const flags = {
process.env.UNLEASH_EXPERIMENTAL_MESSAGE_BANNER,
false,
),
serviceAccounts: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_SERVICE_ACCOUNTS,
false,
),
};

export const defaultExperimentalOptions: IExperimentalOptions = {
Expand Down
3 changes: 3 additions & 0 deletions src/lib/types/permissions.ts
Expand Up @@ -42,3 +42,6 @@ export const DELETE_SEGMENT = 'DELETE_SEGMENT';
export const APPROVE_CHANGE_REQUEST = 'APPROVE_CHANGE_REQUEST';
export const APPLY_CHANGE_REQUEST = 'APPLY_CHANGE_REQUEST';
export const SKIP_CHANGE_REQUEST = 'SKIP_CHANGE_REQUEST';
export const READ_USER_PAT = 'READ_USER_PAT';
export const CREATE_USER_PAT = 'CREATE_USER_PAT';
export const DELETE_USER_PAT = 'DELETE_USER_PAT';
21 changes: 21 additions & 0 deletions src/migrations/20221220160345-user-pat-permissions.js
@@ -0,0 +1,21 @@
exports.up = function (db, cb) {
db.runSql(
`
INSERT INTO permissions (permission, display_name, type) VALUES ('READ_USER_PAT', 'Read PATs for a specific user', 'root');
INSERT INTO permissions (permission, display_name, type) VALUES ('CREATE_USER_PAT', 'Create a PAT for a specific user', 'root');
INSERT INTO permissions (permission, display_name, type) VALUES ('DELETE_USER_PAT', 'Delete a PAT for a specific user', 'root');
`,
cb,
);
};

exports.down = function (db, cb) {
db.runSql(
`
DELETE FROM permissions WHERE permission = 'READ_USER_PAT';
DELETE FROM permissions WHERE permission = 'CREATE_USER_PAT';
DELETE FROM permissions WHERE permission = 'DELETE_USER_PAT';
`,
cb,
);
};
2 changes: 2 additions & 0 deletions src/server-dev.ts
Expand Up @@ -41,6 +41,8 @@ process.nextTick(async () => {
responseTimeWithAppName: true,
changeRequests: true,
variantsPerEnvironment: true,
maintenance: false,
serviceAccounts: true,
},
},
authentication: {
Expand Down

0 comments on commit 88004a6

Please sign in to comment.