Skip to content

Commit

Permalink
feat: Restrict certain users from production environments (#2530)
Browse files Browse the repository at this point in the history
* chore: Add is_staging_only column to users table

* chore: Update sync script

* feat: Check if user can access env

* fix: Typo in migration, comment out sync script

* chore: Bump planx-new
  • Loading branch information
DafyddLlyr authored Dec 6, 2023
1 parent 5131700 commit 1c3fc32
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 132 deletions.
69 changes: 69 additions & 0 deletions api.planx.uk/modules/auth/service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { checkUserCanAccessEnv } from "./service";

const mockIsStagingOnly = jest.fn();

jest.mock("../../client", () => {
return {
$api: {
user: {
isStagingOnly: () => mockIsStagingOnly(),
},
},
};
});

describe("canUserAccessEnv() helper function", () => {
describe("a staging-only user", () => {
beforeAll(() => mockIsStagingOnly.mockResolvedValue(true));

test("can't access production", async () => {
const result = await checkUserCanAccessEnv(
"[email protected]",
"production",
);
expect(result).toBe(false);
});

test("can access staging", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "staging");
expect(result).toBe(true);
});

test("can access pizzas", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "pizza");
expect(result).toBe(true);
});

test("can access test envs", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "test");
expect(result).toBe(true);
});
});

describe("a non staging-only user", () => {
beforeAll(() => mockIsStagingOnly.mockResolvedValue(false));

test("can access production", async () => {
const result = await checkUserCanAccessEnv(
"[email protected]",
"production",
);
expect(result).toBe(true);
});

test("can access staging", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "staging");
expect(result).toBe(true);
});

test("can access pizzas", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "pizza");
expect(result).toBe(true);
});

test("can access test envs", async () => {
const result = await checkUserCanAccessEnv("[email protected]", "test");
expect(result).toBe(true);
});
});
});
14 changes: 14 additions & 0 deletions api.planx.uk/modules/auth/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { $api } from "../../client";
import { User, Role } from "@opensystemslab/planx-core/types";

export const buildJWT = async (email: string): Promise<string | undefined> => {
await checkUserCanAccessEnv(email, process.env.NODE_ENV);
const user = await $api.user.getByEmail(email);
if (!user) return;

Expand Down Expand Up @@ -59,3 +60,16 @@ const getAllowedRolesForUser = (user: User): Role[] => {
const getDefaultRoleForUser = (user: User): Role => {
return user.isPlatformAdmin ? "platformAdmin" : "teamEditor";
};

/**
* A staging-only user cannot access production, but can access all other envs
*/
export const checkUserCanAccessEnv = async (
email: string,
env?: string,
): Promise<boolean> => {
const isStagingOnlyUser = await $api.user.isStagingOnly(email);
const isProductionEnv = env === "production";
const userCanAccessEnv = !(isProductionEnv && isStagingOnlyUser);
return userCanAccessEnv;
};
2 changes: 1 addition & 1 deletion api.planx.uk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"@airbrake/node": "^2.1.8",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#415ae86",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#b78ca10",
"@types/isomorphic-fetch": "^0.0.36",
"adm-zip": "^0.5.10",
"aws-sdk": "^2.1467.0",
Expand Down
17 changes: 9 additions & 8 deletions api.planx.uk/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/tests/api-driven/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"dependencies": {
"@cucumber/cucumber": "^9.3.0",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#415ae86",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#b78ca10",
"axios": "^1.6.0",
"dotenv": "^16.3.1",
"dotenv-expand": "^10.0.0",
Expand Down
16 changes: 8 additions & 8 deletions e2e/tests/api-driven/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/tests/ui-driven/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"postinstall": "./install-dependencies.sh"
},
"dependencies": {
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#415ae86",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#b78ca10",
"axios": "^1.6.0",
"dotenv": "^16.3.1",
"eslint": "^8.44.0",
Expand Down
16 changes: 8 additions & 8 deletions e2e/tests/ui-driven/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion editor.planx.uk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@mui/styles": "^5.14.5",
"@mui/utils": "^5.14.5",
"@opensystemslab/map": "^0.7.5",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#415ae86",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#b78ca10",
"@tiptap/core": "^2.0.3",
"@tiptap/extension-bold": "^2.0.3",
"@tiptap/extension-bubble-menu": "^2.1.6",
Expand Down
Loading

0 comments on commit 1c3fc32

Please sign in to comment.