Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
e622fff
permissions
Sep 23, 2024
cea69ff
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 23, 2024
54be747
step 2
Sep 23, 2024
16cd65d
files
Sep 23, 2024
9930e56
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Sep 26, 2024
6a14873
Merge branch 'eng-1336-custom-override-permissions' of https://github…
Sep 26, 2024
921241d
more route work
Sep 26, 2024
a19fa91
First route
Oct 1, 2024
35c0355
Routes made and tests. setOverride not working
Oct 3, 2024
f30d350
broken tests
Oct 3, 2024
ba6e5ce
docs start
Oct 4, 2024
4dff8d0
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 5, 2024
93d1051
save changes
Oct 10, 2024
258436c
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 10, 2024
3ca0f80
works
Oct 10, 2024
ee4131b
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 10, 2024
c921762
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 15, 2024
f812fd3
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 15, 2024
cf1ce1c
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 15, 2024
f6fcd91
remove docs for PR submittal
Oct 15, 2024
d516bc7
Merge branch 'eng-1336-custom-override-permissions' of https://github…
Oct 15, 2024
775715f
Update apps/api/src/routes/v1_ratelimit_deleteOverride.ts
MichaelUnkey Oct 15, 2024
d10d36c
Update apps/api/src/routes/v1_ratelimit_deleteOverride.ts
MichaelUnkey Oct 15, 2024
9fd380f
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 15, 2024
730d661
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 16, 2024
b6519f1
Update apps/api/src/routes/v1_ratelimit_listOverrides.ts
MichaelUnkey Oct 16, 2024
eacb3b6
response message changed
Oct 16, 2024
5828b35
Merge branch 'eng-1336-custom-override-permissions' of https://github…
Oct 16, 2024
991edce
fixed build error
Oct 16, 2024
56b8c75
Merge branch 'main' into eng-1336-custom-override-permissions
MichaelUnkey Oct 16, 2024
e961f82
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 22, 2024
1dd6470
Update apps/api/src/routes/v1_ratelimit_deleteOverride.ts
MichaelUnkey Oct 23, 2024
652b5d3
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Oct 31, 2024
1654e11
Git Comment changes
Nov 4, 2024
5974580
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Nov 4, 2024
a8818fd
store
Nov 4, 2024
2452892
backup
Nov 7, 2024
b83f336
back
Nov 7, 2024
2c84335
revert stash
Nov 7, 2024
c6896e9
set route working
Nov 7, 2024
fcbc029
get list and set routes
Nov 7, 2024
77093db
mod routes no errors
Nov 8, 2024
4c9a657
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Nov 8, 2024
ef342cc
store after fix
Nov 8, 2024
e2545dc
minor changes
Nov 8, 2024
41c4d20
fmt
Nov 8, 2024
8e238d2
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Nov 12, 2024
6d390a4
Pull and Merge
Nov 12, 2024
3553bc3
happy tests
Nov 13, 2024
45f2732
Merge branch 'main' into eng-1336-custom-override-permissions
MichaelUnkey Nov 13, 2024
61dc582
security tests
Nov 13, 2024
f18588d
Merge branch 'eng-1336-custom-override-permissions' of https://github…
Nov 13, 2024
7fd98d1
missing bracket
Nov 13, 2024
27abeca
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Nov 14, 2024
cb2ca1e
PR changes
Nov 14, 2024
754b87b
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
Nov 15, 2024
8f850bc
Merge branch 'main' of https://github.com/unkeyed/unkey into eng-1336…
chronark Nov 18, 2024
5bca654
chore: clean up
chronark Nov 18, 2024
67e4cf6
fix: prod url
chronark Nov 18, 2024
b2373dd
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 18, 2024
f2336c4
revert: sdk methods
chronark Nov 18, 2024
37dd295
Merge branch 'eng-1336-custom-override-permissions' of https://github…
chronark Nov 18, 2024
9cccdfb
ci: don't log
chronark Nov 18, 2024
0f899c7
fix: put thread in background
chronark Nov 18, 2024
0eb6cfe
chore: clean up
chronark Nov 18, 2024
972f8b0
chore: disable grafana and prometheus
chronark Nov 18, 2024
35bde28
ci: delete unused tools
chronark Nov 18, 2024
b028e6b
chore: disable grafana and prometheus
chronark Nov 18, 2024
65b1d6e
ci
chronark Nov 18, 2024
d575caa
ci
chronark Nov 18, 2024
92fda9a
ci
chronark Nov 18, 2024
117751e
ci
chronark Nov 18, 2024
81999a7
ci
chronark Nov 18, 2024
4bba3bb
ci
chronark Nov 18, 2024
bb27975
ci
chronark Nov 18, 2024
214c61b
ci
chronark Nov 18, 2024
fa3684d
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 18, 2024
24e7238
ci
chronark Nov 18, 2024
8d82f65
Merge branch 'eng-1336-custom-override-permissions' of https://github…
chronark Nov 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
uses: ./.github/actions/install
with:
ts: true

- name: Build
run: pnpm turbo run build --filter=./apps/api

Expand All @@ -31,20 +31,20 @@ jobs:
EOF
working-directory: apps/api
- name: Run worker
run: pnpm dev > api.logs &
run: pnpm dev & sleep 15
working-directory: apps/api



Comment on lines +34 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve worker startup reliability.

The current approach of using sleep 15 has several issues:

  1. The hardcoded delay might not be sufficient on slower systems
  2. It could unnecessarily slow down the workflow on faster systems
  3. There's no verification that the worker is actually ready

Consider implementing a healthcheck or polling mechanism instead.

Example implementation:

-        run: pnpm dev & sleep 15
+        run: |
+          pnpm dev & 
+          PID=$!
+          max_attempts=30
+          attempt=0
+          echo "Waiting for worker to be ready..."
+          while ! curl -s http://localhost:3000/health > /dev/null; do
+            ((attempt++))
+            if [ $attempt -ge $max_attempts ]; then
+              echo "Worker failed to start"
+              kill $PID
+              exit 1
+            fi
+            sleep 1
+          done
+          echo "Worker is ready"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: pnpm dev & sleep 15
working-directory: apps/api
run: |
pnpm dev &
PID=$!
max_attempts=30
attempt=0
echo "Waiting for worker to be ready..."
while ! curl -s http://localhost:3000/health > /dev/null; do
((attempt++))
if [ $attempt -ge $max_attempts ]; then
echo "Worker failed to start"
kill $PID
exit 1
fi
sleep 1
done
echo "Worker is ready"
working-directory: apps/api


- name: Load Schema into MySQL
run: pnpm drizzle-kit push
working-directory: internal/db
env:
DRIZZLE_DATABASE_URL: "mysql://unkey:password@localhost:3306/unkey"



- name: Build
run: pnpm build
env:
Expand All @@ -57,6 +57,3 @@ jobs:
UNKEY_WEBHOOK_KEYS_API_ID: "not-empty"
AGENT_URL: "http://localhost:8080"
AGENT_TOKEN: "not-empty"



3 changes: 0 additions & 3 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ jobs:
uses: ./.github/workflows/test_agent_local.yaml

build_agent_image:
needs:
- agent_local_test
uses: ./.github/workflows/job_build_agent_image.yaml
secrets:
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
Expand Down Expand Up @@ -41,7 +39,6 @@ jobs:

agent_staging_deployment:
needs:
- agent_local_test
- build_agent_image
uses: ./.github/workflows/job_deploy_agent_staging.yaml
secrets:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/job_test_api_local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Delete huge unnecessary tools folder
run: rm -rf /opt/hostedtoolcache


- name: Run containers
run: docker compose -f ./deployment/docker-compose.yaml up -d

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
jobs:
test_packages:
name: Test Packages
uses: ./.github/workflows/unit_test.yaml
uses: ./.github/workflows/job_test_unit.yaml

build:
name: Build
Expand Down
3 changes: 0 additions & 3 deletions apps/api/src/pkg/keys/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,6 @@ export class KeyService {
return Ok({ valid: false, code: "NOT_FOUND" });
}

this.logger.info("data from cache or db", {
data,
});
// Quick fix
if (!data.workspace) {
this.logger.warn("workspace not found, trying again", {
Expand Down
6 changes: 5 additions & 1 deletion apps/api/src/routes/v1_keys_getVerifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const registerV1KeysGetVerifications = (app: App) =>
app.openapi(route, async (c) => {
const { keyId, ownerId, start, end } = c.req.valid("query");

const { analytics, cache, db } = c.get("services");
const { analytics, cache, db, logger } = c.get("services");

const ids: {
keyId: string;
Expand Down Expand Up @@ -240,6 +240,10 @@ export const registerV1KeysGetVerifications = (app: App) =>
[time: number]: { success: number; rateLimited: number; usageExceeded: number };
} = {};
for (const dataPoint of verificationsFromAllKeys) {
if (dataPoint.err) {
logger.error(dataPoint.err.message);
continue;
}
for (const d of dataPoint.val!) {
if (!verifications[d.time]) {
verifications[d.time] = { success: 0, rateLimited: 0, usageExceeded: 0 };
Expand Down
57 changes: 57 additions & 0 deletions apps/api/src/routes/v1_ratelimits_deleteOverride.error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect, test } from "vitest";

import { randomUUID } from "node:crypto";
import { IntegrationHarness } from "src/pkg/testutil/integration-harness";

import { schema } from "@unkey/db";
import { newId } from "@unkey/id";
import type {
V1RatelimitDeleteOverrideRequest,
V1RatelimitDeleteOverrideResponse,
} from "./v1_ratelimits_deleteOverride";

test("Missing Namespace", async (t) => {
const h = await IntegrationHarness.init(t);

const overrideId = newId("test");
const identifier = randomUUID();
const namespaceId = newId("test");
const namespace = {
id: namespaceId,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
name: newId("test"),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);

await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId,
identifier,
limit: 1,
duration: 60_000,
async: false,
});

const root = await h.createRootKey(["ratelimit.*.delete_override"]);
const res = await h.post<V1RatelimitDeleteOverrideRequest, V1RatelimitDeleteOverrideResponse>({
url: "/v1/ratelimits.deleteOverride",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
identifier,
},
});

expect(res.status, `expected 400, received: ${JSON.stringify(res, null, 2)}`).toBe(400);
expect(res.body).toMatchObject({
error: {
code: "BAD_REQUEST",
docs: "https://unkey.dev/docs/api-reference/errors/code/BAD_REQUEST",
message: "You must provide a namespaceId or a namespaceName",
},
});
});
56 changes: 56 additions & 0 deletions apps/api/src/routes/v1_ratelimits_deleteOverride.happy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { expect, test } from "vitest";

import { randomUUID } from "node:crypto";
import { IntegrationHarness } from "src/pkg/testutil/integration-harness";

import { isNull, schema } from "@unkey/db";
import { newId } from "@unkey/id";
import type {
V1RatelimitDeleteOverrideRequest,
V1RatelimitDeleteOverrideResponse,
} from "./v1_ratelimits_deleteOverride";

test("deletes override", async (t) => {
const h = await IntegrationHarness.init(t);

const overrideId = newId("test");
const identifier = randomUUID();
const namespaceId = newId("test");
const namespace = {
id: namespaceId,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
name: newId("test"),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);

await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId,
identifier,
limit: 1,
duration: 60_000,
async: false,
});

const root = await h.createRootKey(["ratelimit.*.delete_override"]);
const res = await h.post<V1RatelimitDeleteOverrideRequest, V1RatelimitDeleteOverrideResponse>({
url: "/v1/ratelimits.deleteOverride",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
namespaceId,
identifier,
},
});

expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);

const found = await h.db.primary.query.ratelimitOverrides.findFirst({
where: (table, { eq, and }) => and(eq(table.id, overrideId), isNull(table.deletedAt)),
});
expect(found).toBeUndefined();
});
158 changes: 158 additions & 0 deletions apps/api/src/routes/v1_ratelimits_deleteOverride.security.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { randomUUID } from "node:crypto";
import { runCommonRouteTests } from "@/pkg/testutil/common-tests";
import { IntegrationHarness } from "@/pkg/testutil/integration-harness";
import { schema } from "@unkey/db";
import { newId } from "@unkey/id";
import { describe, expect, test } from "vitest";
import type {
V1RatelimitDeleteOverrideRequest,
V1RatelimitDeleteOverrideResponse,
} from "./v1_ratelimits_deleteOverride";

runCommonRouteTests<V1RatelimitDeleteOverrideRequest>({
prepareRequest: async (rh) => {
const overrideId = newId("test");
const identifier = randomUUID();
const namespaceId = newId("test");
const namespace = {
id: namespaceId,
workspaceId: rh.resources.userWorkspace.id,
createdAt: new Date(),
name: newId("test"),
};
await rh.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
await rh.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: rh.resources.userWorkspace.id,
namespaceId,
identifier,
limit: 1,
duration: 60_000,
async: false,
});

return {
method: "POST",
url: "/v1/ratelimits.deleteOverride",
headers: {
"Content-Type": "application/json",
},
body: {
namespaceId,
identifier,
},
};
},
});
describe("correct roles", () => {
describe.each([{ name: "delete override", roles: ["ratelimit.*.delete_override"] }])(
"$name",
({ roles }) => {
test("returns 200", async (t) => {
const h = await IntegrationHarness.init(t);
const overrideId = newId("test");
const identifier = randomUUID();
const namespaceId = newId("test");
const namespace = {
id: namespaceId,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
name: newId("test"),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId,
identifier,
limit: 1,
duration: 60_000,
async: false,
});
const root = await h.createRootKey(roles);

const res = await h.post<
V1RatelimitDeleteOverrideRequest,
V1RatelimitDeleteOverrideResponse
>({
url: "/v1/ratelimits.deleteOverride",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
namespaceId,
identifier,
},
});

expect(
res.status,
`expected status 200, received: ${JSON.stringify(res, null, 2)}`,
).toEqual(200);

const found = await h.db.primary.query.ratelimitOverrides.findFirst({
where: (table, { eq, and, isNull }) =>
and(isNull(table.deletedAt), eq(table.id, overrideId)),
});
expect(found).toBeUndefined();
});
},
);
});

describe("incorrect roles", () => {
describe.each([{ name: "delete override", roles: ["ratelimit.*.create_override"] }])(
"$name",
({ roles }) => {
test("returns 403", async (t) => {
const h = await IntegrationHarness.init(t);
const overrideId = newId("test");
const identifier = randomUUID();
const namespaceId = newId("test");
const namespace = {
id: namespaceId,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
name: newId("test"),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId,
identifier,
limit: 1,
duration: 60_000,
async: false,
});
const root = await h.createRootKey(roles);

const res = await h.post<
V1RatelimitDeleteOverrideRequest,
V1RatelimitDeleteOverrideResponse
>({
url: "/v1/ratelimits.deleteOverride",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
namespaceId,
identifier,
},
});

expect(
res.status,
`expected status 403, received: ${JSON.stringify(res, null, 2)}`,
).toEqual(403);

const found = await h.db.primary.query.ratelimitOverrides.findFirst({
where: (table, { eq }) => eq(table.id, overrideId),
});
expect(found?.id).toEqual(overrideId);
});
},
);
});
Loading