Skip to content

Commit

Permalink
[server] more project service (#18157)
Browse files Browse the repository at this point in the history
- more testing
- throw 404 instead of undefined
- more permission checks
  • Loading branch information
svenefftinge authored Jul 4, 2023
1 parent d7aa23e commit 66e0cf2
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 78 deletions.
6 changes: 3 additions & 3 deletions components/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
"lint": "yarn eslint src/**/*.ts",
"format": "yarn eslint src/**/*.ts --fix",
"test": ". $(leeway run components/gitpod-db:db-test-env) && TS_NODE_FILES=true mocha --opts mocha.opts './**/*.spec.ts' --exclude './node_modules/**'",
"spicedb-testing": "if netstat -tuln | grep ':50051 '; then echo '`spicedb serve-testing` is already running.'; else spicedb serve-testing --load-configs /workspace/gitpod/install/installer/pkg/components/spicedb/data/schema.yaml; fi",
"stop-spicedb-testing": "PID=$(lsof -t -i:50051); if [ -z \"$PID\" ]; then echo '`spicedb serve-testing` is not running'; else kill -INT $PID && echo 'Stopped `spicedb serve-testing`'; fi",
"db-test": "r(){ . $(leeway run components/gitpod-db:db-test-env); yarn spicedb-testing & yarn db-test-run; yarn stop-spicedb-testing; };r",
"start-spicedb": "if netstat -tuln | grep ':50051 '; then echo '`spicedb serve-testing` is already running.'; else spicedb serve-testing --load-configs /workspace/gitpod/install/installer/pkg/components/spicedb/data/schema.yaml; fi",
"stop-spicedb": "PID=$(lsof -t -i:50051); if [ -z \"$PID\" ]; then echo '`spicedb serve-testing` is not running'; else kill -INT $PID && echo 'Stopped `spicedb serve-testing`'; fi",
"db-test": "r(){ . $(leeway run components/gitpod-db:db-test-env); yarn start-spicedb & yarn db-test-run; yarn stop-spicedb; };r",
"db-test-run": "TS_NODE_FILES=true mocha --opts mocha.opts '**/*.spec.db.ts' --exclude './node_modules/**'",
"telepresence": "telepresence --swap-deployment server --method inject-tcp --run yarn start-inspect"
},
Expand Down
89 changes: 71 additions & 18 deletions components/server/src/projects/projects-service.spec.db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { Experiments } from "@gitpod/gitpod-protocol/lib/experiments/configcat-s
import * as chai from "chai";
import { Container } from "inversify";
import "mocha";
import { ResponseError } from "vscode-ws-jsonrpc";
import { OrganizationService } from "../orgs/organization-service";
import { serviceTestingContainerModule } from "../test/service-testing-container-module";
import { ProjectsService } from "./projects-service";
import { ApplicationError, ErrorCode, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";

const expect = chai.expect;

describe("ProjectsService", async () => {
let container: Container;
let owner: User;
let member: User;
let stranger: User;
let org: Organization;

Expand All @@ -33,9 +34,12 @@ describe("ProjectsService", async () => {
});
const userDB = container.get<UserDB>(UserDB);
owner = await userDB.newUser();
member = await userDB.newUser();
stranger = await userDB.newUser();
const orgService = container.get(OrganizationService);
org = await orgService.createOrganization(owner.id, "my-org");
const invite = await orgService.getOrCreateInvite(owner.id, org.id);
await orgService.joinOrganization(member.id, invite.id);
});

afterEach(async () => {
Expand Down Expand Up @@ -63,37 +67,73 @@ describe("ProjectsService", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);

const foundProject = await ps.getProject(stranger.id, project.id);
expect(foundProject).to.be.undefined;

const projects = await ps.getProjects(stranger.id, project.id);
expect(projects.length).to.equal(0);
await expectError(ErrorCodes.NOT_FOUND, () => ps.getProject(stranger.id, project.id));
await expectError(ErrorCodes.NOT_FOUND, () => ps.getProjects(stranger.id, org.id));
});

it("should not let strangers find projects", async () => {
it("should not let strangers delete projects", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);

try {
await ps.deleteProject(stranger.id, project.id);
expect.fail("should not be able to delete projects");
} catch (error) {
ResponseError;
expect(error).to.not.be.undefined;
}
await expectError(ErrorCodes.NOT_FOUND, () => ps.deleteProject(stranger.id, project.id));
});

it("should let owners delete their projects", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);
await ps.deleteProject(owner.id, project.id);

let foundProject = await ps.getProject(owner.id, project.id);
expect(foundProject).to.be.undefined;
await expectError(ErrorCodes.NOT_FOUND, () => ps.getProject(owner.id, project.id));

const projects = await ps.getProjects(owner.id, org.id);
expect(projects.length).to.equal(0);
});

it("should let owners update their project settings", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);
await ps.updateProjectPartial(owner.id, {
id: project.id,
settings: {
useIncrementalPrebuilds: !project.settings?.useIncrementalPrebuilds,
},
});

const updatedProject = await ps.getProject(owner.id, project.id);

expect(updatedProject?.settings?.useIncrementalPrebuilds).to.not.equal(
project.settings?.useIncrementalPrebuilds,
);
});

it("should not let members update project settings", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);

await expectError(ErrorCodes.PERMISSION_DENIED, () =>
ps.updateProjectPartial(member.id, {
id: project.id,
settings: {
useIncrementalPrebuilds: !project.settings?.useIncrementalPrebuilds,
},
}),
);
});

it("should not let strangers update project settings", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);

await expectError(ErrorCodes.NOT_FOUND, () =>
ps.updateProjectPartial(stranger.id, {
id: project.id,
settings: {
useIncrementalPrebuilds: !project.settings?.useIncrementalPrebuilds,
},
}),
);
});

it("should let owners create, delete and get project env vars", async () => {
const ps = container.get(ProjectsService);
const project = await createTestProject(ps, org, owner);
Expand Down Expand Up @@ -132,19 +172,32 @@ describe("ProjectsService", async () => {
await ps.deleteProjectEnvironmentVariable(stranger.id, envVars[0].id);
expect.fail("should not be able to delete env var as stranger");
} catch (error) {
expect(error.message).to.contain("not found");
expectErrorCode(error, ErrorCodes.NOT_FOUND);
}

// let's try to get the env vars as a stranger
try {
await ps.getProjectEnvironmentVariables(stranger.id, project.id);
expect.fail("should not be able to get env vars as stranger");
} catch (error) {
expect(error.message).to.contain("not found");
expectErrorCode(error, ErrorCodes.NOT_FOUND);
}
});
});

async function expectError(errorCode: ErrorCode, code: () => Promise<any>) {
try {
await code();
expect.fail("expected error: " + errorCode);
} catch (error) {
expectErrorCode(error, errorCode);
}
}

function expectErrorCode(err: any, errorCode: ErrorCode) {
expect(err && ApplicationError.hasErrorCode(err) && err.code).to.equal(errorCode);
}

async function createTestProject(ps: ProjectsService, org: Organization, owner: User) {
return await ps.createProject(
{
Expand Down
Loading

0 comments on commit 66e0cf2

Please sign in to comment.