@runuai/host 0.9.11 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/migrations/0013_github_credential_generations.sql +11 -0
- package/db/migrations/meta/_journal.json +7 -0
- package/db/schema.ts +18 -0
- package/lib/env.ts +6 -1
- package/lib/github-tokens.ts +633 -69
- package/package.json +1 -1
- package/src/event-outbox.ts +104 -0
- package/src/main.ts +299 -29
- package/src/protocol.ts +123 -6
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ALTER TABLE `host_github_tokens` ADD `generation` integer DEFAULT 0 NOT NULL;
|
|
2
|
+
--> statement-breakpoint
|
|
3
|
+
CREATE TABLE `host_github_credential_generations` (
|
|
4
|
+
`user_id` text PRIMARY KEY NOT NULL,
|
|
5
|
+
`generation` integer DEFAULT 0 NOT NULL,
|
|
6
|
+
`mutation` text DEFAULT 'set' NOT NULL,
|
|
7
|
+
`updated_at` integer NOT NULL
|
|
8
|
+
);
|
|
9
|
+
--> statement-breakpoint
|
|
10
|
+
INSERT INTO `host_github_credential_generations` (`user_id`, `generation`, `mutation`, `updated_at`)
|
|
11
|
+
SELECT `user_id`, 0, 'set', `updated_at` FROM `host_github_tokens`;
|
|
@@ -92,6 +92,13 @@
|
|
|
92
92
|
"when": 1779900013000,
|
|
93
93
|
"tag": "0012_agent_session_attach_key",
|
|
94
94
|
"breakpoints": true
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"idx": 13,
|
|
98
|
+
"version": "6",
|
|
99
|
+
"when": 1786045000000,
|
|
100
|
+
"tag": "0013_github_credential_generations",
|
|
101
|
+
"breakpoints": true
|
|
95
102
|
}
|
|
96
103
|
]
|
|
97
104
|
}
|
package/db/schema.ts
CHANGED
|
@@ -62,6 +62,11 @@ export type NewHostEventRow = typeof hostEvents.$inferInsert;
|
|
|
62
62
|
export const githubTokens = sqliteTable("host_github_tokens", {
|
|
63
63
|
userId: text("user_id").primaryKey(),
|
|
64
64
|
installationId: integer("installation_id").notNull(),
|
|
65
|
+
/** Generation of the cloud binding whose credential this row contains.
|
|
66
|
+
* Readers trust the token only while it matches the durable mutation fence
|
|
67
|
+
* below, so a crash between claiming a newer generation and deleting this
|
|
68
|
+
* row leaves a safely inert old ciphertext rather than a usable old token. */
|
|
69
|
+
generation: integer("generation").notNull().default(0),
|
|
65
70
|
// ADR-033: holds a long-lived ACCESS token when kind="access", or a refresh
|
|
66
71
|
// token when kind="refresh" (legacy ADR-027). Encrypted at rest either way.
|
|
67
72
|
refreshTokenCt: blob("refresh_token_ct").notNull(),
|
|
@@ -75,6 +80,19 @@ export const githubTokens = sqliteTable("host_github_tokens", {
|
|
|
75
80
|
export type GithubToken = typeof githubTokens.$inferSelect;
|
|
76
81
|
export type NewGithubToken = typeof githubTokens.$inferInsert;
|
|
77
82
|
|
|
83
|
+
// Durable monotonic tombstone for GitHub credential mutations. Kept separate
|
|
84
|
+
// from the token row so a disconnect can reject a delayed older connect even
|
|
85
|
+
// after the encrypted credential itself has been deleted.
|
|
86
|
+
export const githubCredentialGenerations = sqliteTable(
|
|
87
|
+
"host_github_credential_generations",
|
|
88
|
+
{
|
|
89
|
+
userId: text("user_id").primaryKey(),
|
|
90
|
+
generation: integer("generation").notNull().default(0),
|
|
91
|
+
mutation: text("mutation").notNull().default("set"),
|
|
92
|
+
updatedAt: integer("updated_at").notNull(),
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
|
|
78
96
|
// Per-user ed25519 SSH key (ADR-029). Generated ON the host; the private key
|
|
79
97
|
// lives encrypted at rest with the host master key (same secret-blind pattern
|
|
80
98
|
// as host_github_tokens — ADR-015). The cloud only ever sees `public_key`,
|
package/lib/env.ts
CHANGED
|
@@ -22,9 +22,14 @@ const schema = z.object({
|
|
|
22
22
|
UAI_HOST_ID: z.string().min(1).optional(),
|
|
23
23
|
// Host master key file (ADR-027) — 32 bytes, AES-256-GCM for the host
|
|
24
24
|
// secret store. Defaults to $UAI_DATA_DIR/host-master.key; generated on
|
|
25
|
-
// first use.
|
|
25
|
+
// first use.
|
|
26
26
|
UAI_HOST_KEY_FILE: z.string().min(1).optional(),
|
|
27
|
+
// Transitional single-user GitHub PAT, for the one user who has not
|
|
28
|
+
// connected GitHub. Inert without UAI_GH_PAT_FALLBACK_USER_ID: the PAT is a
|
|
29
|
+
// host-wide credential, so it may only be injected into tasks owned by the
|
|
30
|
+
// user it belongs to. See setupTaskGithub().
|
|
27
31
|
UAI_GH_PAT_FALLBACK: z.string().min(1).optional(),
|
|
32
|
+
UAI_GH_PAT_FALLBACK_USER_ID: z.string().min(1).optional(),
|
|
28
33
|
UAI_WORKSPACE_ROOT: z.string().min(1).default("~/.uai"),
|
|
29
34
|
// Crash reporting (ADR-071, docs/observability.md). Default-ON for
|
|
30
35
|
// installed hosts via the DSN baked into lib/obs.ts; UAI_SENTRY_DSN
|