feat(523): forge-connection tokens are stored sealed under SECRET_KEY, like the backup S3 secret
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 1m8s
CI & Build / Python tests (push) Successful in 1m54s
CI & Build / Build & push image (push) Successful in 36s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 1m8s
CI & Build / Python tests (push) Successful in 1m54s
CI & Build / Build & push image (push) Successful in 36s
The column becomes token_sealed (migration 0122 seals existing rows with a frozen copy of the v1 key), every reader opens it through connection_token, a row this instance cannot open is skipped with a warning, and Settings asks for that token again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -825,14 +825,17 @@ const baseUrlSaved = ref(false);
|
||||
// Git forge connections (#2778) — the user's keyring: one read-only
|
||||
// credential per forge host, used server-side for every forge read on
|
||||
// projects this user owns. The token round-trips masked; the server treats
|
||||
// the mask as "unchanged".
|
||||
// the mask as "unchanged". Tokens are stored sealed under SECRET_KEY:
|
||||
// `token_readable` false means this instance can no longer open one (the key
|
||||
// changed since it was saved), so the row asks for it again.
|
||||
interface ForgeConnectionEntry {
|
||||
id: number; kind: string; base_url: string; host: string;
|
||||
id: number; kind: string; base_url: string; host: string; token_readable: boolean;
|
||||
}
|
||||
const forgeConnections = ref<ForgeConnectionEntry[]>([]);
|
||||
const forgeKinds = ref<string[]>(["gitea", "github"]);
|
||||
const connForm = ref({ id: 0, kind: "gitea", base_url: "", token: "" });
|
||||
const connFormOpen = ref(false);
|
||||
const unreadableConnections = computed(() => forgeConnections.value.filter((c) => !c.token_readable));
|
||||
const savingConn = ref(false);
|
||||
const testingConnId = ref(0);
|
||||
const connTestResult = ref<{ id: number; ok: boolean; message: string } | null>(null);
|
||||
@@ -2564,13 +2567,23 @@ async function deleteUser(userId: number) {
|
||||
Read-only, base URL <code>https://github.com</code> (or your GitHub
|
||||
Enterprise URL).
|
||||
</p>
|
||||
<p v-if="unreadableConnections.length" class="calibration-warning" role="alert">
|
||||
{{ unreadableConnections.length === 1 ? "One connection's token" : `${unreadableConnections.length} connections' tokens` }}
|
||||
can't be read on this instance: <code>SECRET_KEY</code> has changed since
|
||||
{{ unreadableConnections.length === 1 ? "it was" : "they were" }} saved. Edit
|
||||
{{ unreadableConnections.map((c) => c.host).join(", ") }} and enter the token again.
|
||||
Until then, forge reads for that host don't run.
|
||||
</p>
|
||||
<table v-if="forgeConnections.length" class="api-keys-table">
|
||||
<thead>
|
||||
<tr><th>Host</th><th>Kind</th><th>Base URL</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="c in forgeConnections" :key="c.id">
|
||||
<td>{{ c.host }}</td>
|
||||
<td>
|
||||
{{ c.host }}
|
||||
<span v-if="!c.token_readable" class="conn-token-lost">token needs re-entering</span>
|
||||
</td>
|
||||
<td>{{ c.kind }}</td>
|
||||
<td><code>{{ c.base_url }}</code></td>
|
||||
<td>
|
||||
@@ -4593,6 +4606,11 @@ async function deleteUser(userId: number) {
|
||||
border-radius: var(--fs-radius-md);
|
||||
background: color-mix(in srgb, var(--fs-warning) 12%, var(--fs-surface-raised));
|
||||
}
|
||||
.conn-token-lost {
|
||||
margin-left: var(--fs-space-2);
|
||||
font-size: var(--fs-size-body-sm);
|
||||
color: var(--fs-warning-fg);
|
||||
}
|
||||
.calibration-warning-title {
|
||||
margin: 0 0 var(--fs-space-2);
|
||||
font-size: 0.95rem;
|
||||
|
||||
Reference in New Issue
Block a user