Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions apps/cli/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export interface TokenInfo {
readonly caches: string[];
readonly perms: string[];
readonly createdAt: string;
readonly expiresAt: string;
readonly expiresAt: string | null;
readonly createdBy: string;
readonly revokedAt: string | null;
readonly revokedBy: string | null;
Expand All @@ -224,7 +224,7 @@ export interface CreateTokenResponse {
readonly subject: string;
readonly caches: string[];
readonly perms: string[];
readonly expiresAt: string;
readonly expiresAt: string | null;
}

export async function createToken(
Expand All @@ -233,7 +233,8 @@ export async function createToken(
subject: string;
caches: string[];
perms: string[];
expiresInDays?: number;
// `null` requests a non-expiring token.
expiresInDays?: number | null;
},
): Promise<CreateTokenResponse> {
const resp = await request(client, "POST", "/_api/v1/admin/tokens", params);
Expand Down
23 changes: 15 additions & 8 deletions apps/cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ Options:
Token create options:
--caches <names> Comma-separated cache names or "*" (default: *)
--perms <perms> Comma-separated permissions (default: push)
--expires <days> Token lifetime in days (default: 90)
--expires <days> Token lifetime in days, or "never" for no expiry (default: 90)

Examples:
helios login prod https://cache.example.com my-admin-secret
helios push main /nix/store/abc...-hello
helios push main --closure /run/current-system
helios token create ci-runner --caches main --perms push --expires 90
helios token create bot --caches main --perms push --expires never
helios token list
helios token revoke a1b2c3d4-... "employee offboarded"
`;
Expand Down Expand Up @@ -155,13 +156,19 @@ async function main(): Promise<void> {
permsStr = args[permsIdx + 1];
}

let expiresInDays: number | undefined;
// undefined: server default. null: never expires. number: lifetime in days.
let expiresInDays: number | null | undefined;
const expiresIdx = args.indexOf("--expires");
if (expiresIdx !== -1 && expiresIdx + 1 < args.length) {
expiresInDays = parseInt(args[expiresIdx + 1], 10);
if (!Number.isInteger(expiresInDays) || expiresInDays < 1) {
console.error("--expires must be a positive integer");
process.exit(1);
const value = args[expiresIdx + 1];
if (value === "never") {
expiresInDays = null;
} else {
expiresInDays = parseInt(value, 10);
if (!Number.isInteger(expiresInDays) || expiresInDays < 1) {
console.error("--expires must be a positive integer or \"never\"");
process.exit(1);
}
}
}

Expand All @@ -173,7 +180,7 @@ async function main(): Promise<void> {
console.log(` JTI: ${result.jti}`);
console.log(` Caches: ${result.caches.join(", ")}`);
console.log(` Perms: ${result.perms.join(", ")}`);
console.log(` Expires: ${result.expiresAt}`);
console.log(` Expires: ${result.expiresAt ?? "never"}`);
console.log("");
console.log(result.token);
return;
Expand All @@ -187,7 +194,7 @@ async function main(): Promise<void> {
}
for (const t of tokens) {
const status = t.revokedAt ? `revoked (${t.revokedAt})` : "active";
console.log(`${t.jti} ${t.subject} [${t.perms.join(",")}] caches=[${t.caches.join(",")}] ${status} expires=${t.expiresAt}`);
console.log(`${t.jti} ${t.subject} [${t.perms.join(",")}] caches=[${t.caches.join(",")}] ${status} expires=${t.expiresAt ?? "never"}`);
}
return;
}
Expand Down
18 changes: 18 additions & 0 deletions workers/cache/migrations/0003_happy_eternity.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_api_tokens` (
`jti` text PRIMARY KEY NOT NULL,
`subject` text NOT NULL,
`caches_json` text NOT NULL,
`perms_json` text NOT NULL,
`created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
`expires_at` text,
`created_by` text NOT NULL,
`revoked_at` text,
`revoked_by` text,
`revocation_reason` text
);
--> statement-breakpoint
INSERT INTO `__new_api_tokens`("jti", "subject", "caches_json", "perms_json", "created_at", "expires_at", "created_by", "revoked_at", "revoked_by", "revocation_reason") SELECT "jti", "subject", "caches_json", "perms_json", "created_at", "expires_at", "created_by", "revoked_at", "revoked_by", "revocation_reason" FROM `api_tokens`;--> statement-breakpoint
DROP TABLE `api_tokens`;--> statement-breakpoint
ALTER TABLE `__new_api_tokens` RENAME TO `api_tokens`;--> statement-breakpoint
PRAGMA foreign_keys=ON;
Loading