ardent-cli-beta 0.1.1 → 0.1.2
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { acknowledgeBranchCredential, ALL_SCHEMAS_PROFILE, composeCredentialDelivery, CredentialIssueRefused, describeUnadmitted, issuedConnectKey,
|
|
2
|
+
import { acknowledgeBranchCredential, ALL_SCHEMAS_PROFILE, composeCredentialDelivery, CredentialIssueRefused, describeUnadmitted, issuedConnectKey, issueBranchCredentialWhenMarked, revokeBranchCredential, waitForBranchCredential } from './credentials.js';
|
|
3
3
|
import { CLIENT_REQUIREMENTS, connectionString } from './drivers.js';
|
|
4
4
|
import { connectionEnvironment, runPsql } from './psql.js';
|
|
5
5
|
import { CredentialRecoveryCleanupError, forgetCredentialRecovery, openCredentialWitness, rememberCredentialIssuance, rememberCredentialRequest } from './recovery.js';
|
|
@@ -29,7 +29,7 @@ export async function connectToBranch(connection) {
|
|
|
29
29
|
let failure;
|
|
30
30
|
try {
|
|
31
31
|
try {
|
|
32
|
-
const issued = await
|
|
32
|
+
const issued = await issueBranchCredentialWhenMarked(token, branchID, requestID, credential, say);
|
|
33
33
|
issuanceID = issued.issuanceID;
|
|
34
34
|
await rememberCredentialIssuance(recovery, issuanceID);
|
|
35
35
|
connectKey = issuedConnectKey(issued);
|
|
@@ -41,6 +41,7 @@ export type CredentialRequest = {
|
|
|
41
41
|
export declare function validSourceRole(role: string): boolean;
|
|
42
42
|
export declare function refusedBeforeIssuance(error: unknown): boolean;
|
|
43
43
|
export declare function issueBranchCredential(token: string, branchID: string, requestID: string, credential: CredentialRequest): Promise<IssuedCredential>;
|
|
44
|
+
export declare function issueBranchCredentialWhenMarked(token: string, branchID: string, requestID: string, credential: CredentialRequest, say: (message: string) => void): Promise<IssuedCredential>;
|
|
44
45
|
export declare function issuedConnectKey(issued: IssuedCredential): string | undefined;
|
|
45
46
|
export declare function composeCredentialDelivery(delivered: DeliveredCredential, connectKey?: string): DeliveredCredential;
|
|
46
47
|
export declare function waitForBranchCredential(token: string, issuanceID: string, stop?: AbortSignal, served?: Promise<void>): Promise<DeliveredCredential>;
|
|
@@ -9,10 +9,18 @@ export class CredentialIssueRefused extends Error {
|
|
|
9
9
|
this.code = code;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
// branch_mark_pending is a branch registered ahead of its covering mark. The
|
|
13
|
+
// API refuses its credential before recording anything, and the same request
|
|
14
|
+
// is accepted once the mark binds (issueBranchCredentialWhenMarked).
|
|
15
|
+
const MARK_PENDING = 'branch_mark_pending';
|
|
16
|
+
// How long a credential wait lasts once nothing outside it bounds it: the wait
|
|
17
|
+
// for a branch to bind its covering mark, and the wait for delivery once the
|
|
18
|
+
// branch serves.
|
|
19
|
+
const WAIT_BOUND_MS = 10 * 60 * 1000;
|
|
12
20
|
// The issuance refusals that come before any issuance is recorded: a request
|
|
13
21
|
// refused with one of these left nothing to revoke.
|
|
14
22
|
const issueRefusals = new Set(['invalid_source_role', 'source_role_unsupported', 'source_role_held', 'source_role_revocation_pending', 'connect_key_unsupported',
|
|
15
|
-
'all_schemas_read_write_unsupported', 'all_schemas_read_write_unowned']);
|
|
23
|
+
'all_schemas_read_write_unsupported', 'all_schemas_read_write_unowned', MARK_PENDING]);
|
|
16
24
|
// The access profile branch connect asks for without --role, and the one an
|
|
17
25
|
// earlier release of this CLI asked for, which a recovery record naming no
|
|
18
26
|
// profile replays.
|
|
@@ -74,6 +82,33 @@ export async function issueBranchCredential(token, branchID, requestID, credenti
|
|
|
74
82
|
// records and revokes an issuance even when its secret is absent or malformed.
|
|
75
83
|
return { issuanceID: result.issuance_id, connectKey: result.connect_key, connectKeyRequired: result.connect_key_required };
|
|
76
84
|
}
|
|
85
|
+
// issueBranchCredentialWhenMarked is issueBranchCredential for a branch that
|
|
86
|
+
// may still be waiting for its covering mark: a branch_mark_pending refusal
|
|
87
|
+
// sends the same request again on the poll cadence, saying so once, until the
|
|
88
|
+
// API accepts it or ten minutes pass. Every other refusal is thrown as it
|
|
89
|
+
// came. Credential recovery calls issueBranchCredential instead, since a
|
|
90
|
+
// branch_mark_pending answer already tells it there is nothing to revoke.
|
|
91
|
+
export async function issueBranchCredentialWhenMarked(token, branchID, requestID, credential, say) {
|
|
92
|
+
const deadline = Date.now() + WAIT_BOUND_MS;
|
|
93
|
+
const pause = pollPauser();
|
|
94
|
+
let announced = false;
|
|
95
|
+
for (;;) {
|
|
96
|
+
try {
|
|
97
|
+
return await issueBranchCredential(token, branchID, requestID, credential);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (!(error instanceof CredentialIssueRefused) || error.code !== MARK_PENDING)
|
|
101
|
+
throw error;
|
|
102
|
+
if (Date.now() >= deadline) {
|
|
103
|
+
throw new CredentialIssueRefused(`Timed out after ten minutes waiting for the branch's snapshot, so no credential was issued. Check branch status before trying again. ${error.message}`, MARK_PENDING);
|
|
104
|
+
}
|
|
105
|
+
if (!announced)
|
|
106
|
+
say('Waiting for the branch\'s snapshot...');
|
|
107
|
+
announced = true;
|
|
108
|
+
await pause();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
77
112
|
export function issuedConnectKey(issued) {
|
|
78
113
|
if (issued.connectKeyRequired === undefined || issued.connectKeyRequired === false) {
|
|
79
114
|
if (issued.connectKey !== undefined)
|
|
@@ -129,7 +164,7 @@ export function composeCredentialDelivery(delivered, connectKey) {
|
|
|
129
164
|
// since the control plane delivers nothing before it, and until then the wait
|
|
130
165
|
// is bounded by whatever bounds served.
|
|
131
166
|
export async function waitForBranchCredential(token, issuanceID, stop, served) {
|
|
132
|
-
const bound =
|
|
167
|
+
const bound = WAIT_BOUND_MS;
|
|
133
168
|
let deadline = served ? Number.POSITIVE_INFINITY : Date.now() + bound;
|
|
134
169
|
served?.then(() => { deadline = Date.now() + bound; }, () => { });
|
|
135
170
|
// A 202 is re-read on the poll cadence; a 5xx or a lost response is retried
|
package/oclif.manifest.json
CHANGED