@groundtrack/hooks 0.1.14 → 0.1.15
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.
|
@@ -24,7 +24,8 @@ Import options:
|
|
|
24
24
|
--since DATE Import sessions at or after an ISO timestamp or local YYYY-MM-DD
|
|
25
25
|
--include-subagents Include subagent, forked-agent, and guardian sessions
|
|
26
26
|
--visibility VALUE private (default) or organization
|
|
27
|
-
--api-key KEY API key; prefer
|
|
27
|
+
--api-key KEY API key; prefer GROUNDTRACK_IMPORT_KEY or GROUNDTRACK_API_KEY
|
|
28
|
+
--receipt-scope VALUE Stable receipt scope from create_session_import_key for rotating keys
|
|
28
29
|
--url URL Groundtrack app or API URL (default: https://app.groundtrack.dev)
|
|
29
30
|
--dry-run Discover and prune without authentication or network calls
|
|
30
31
|
--yes, -y Upload without another confirmation
|
|
@@ -68,6 +69,7 @@ export function parseImportArguments(argv) {
|
|
|
68
69
|
let yes = false;
|
|
69
70
|
let json = false;
|
|
70
71
|
let apiKey;
|
|
72
|
+
let receiptScope;
|
|
71
73
|
let apiBaseUrl = normalizeApiBaseUrl("https://app.groundtrack.dev");
|
|
72
74
|
let help = false;
|
|
73
75
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -98,6 +100,8 @@ export function parseImportArguments(argv) {
|
|
|
98
100
|
since = parseDate(valueAfter(index++, arg));
|
|
99
101
|
else if (arg === "--api-key")
|
|
100
102
|
apiKey = valueAfter(index++, arg);
|
|
103
|
+
else if (arg === "--receipt-scope")
|
|
104
|
+
receiptScope = valueAfter(index++, arg);
|
|
101
105
|
else if (arg === "--url")
|
|
102
106
|
apiBaseUrl = normalizeApiBaseUrl(valueAfter(index++, arg));
|
|
103
107
|
else if (arg === "--dry-run")
|
|
@@ -128,6 +132,7 @@ export function parseImportArguments(argv) {
|
|
|
128
132
|
yes,
|
|
129
133
|
json,
|
|
130
134
|
apiKey,
|
|
135
|
+
receiptScope,
|
|
131
136
|
apiBaseUrl,
|
|
132
137
|
help,
|
|
133
138
|
};
|
|
@@ -216,7 +221,12 @@ async function runAgentImport(args, agent, context, interactive) {
|
|
|
216
221
|
workingDirectory: context.repoDir,
|
|
217
222
|
});
|
|
218
223
|
try {
|
|
219
|
-
const apiKey = args.apiKey ?? context.env.GROUNDTRACK_API_KEY;
|
|
224
|
+
const apiKey = args.apiKey ?? context.env.GROUNDTRACK_IMPORT_KEY ?? context.env.GROUNDTRACK_API_KEY;
|
|
225
|
+
const providedReceiptScope = args.receiptScope ?? context.env.GROUNDTRACK_IMPORT_RECEIPT_SCOPE;
|
|
226
|
+
if (providedReceiptScope && !/^[a-f0-9]{64}$/.test(providedReceiptScope))
|
|
227
|
+
throw new Error("The import receipt scope must be a 64-character lowercase hex value.");
|
|
228
|
+
// A leftover scope from another import must not skip uploads with a legacy key.
|
|
229
|
+
const stableReceiptScope = apiKey?.startsWith("gti_") ? providedReceiptScope : undefined;
|
|
220
230
|
const receipts = apiKey ? readReceipts(context) : { version: 1, receipts: {} };
|
|
221
231
|
const prepared = [];
|
|
222
232
|
const preparationErrors = [...discovery.failed];
|
|
@@ -232,6 +242,7 @@ async function runAgentImport(args, agent, context, interactive) {
|
|
|
232
242
|
? receiptKey({
|
|
233
243
|
apiBaseUrl: args.apiBaseUrl,
|
|
234
244
|
apiKey,
|
|
245
|
+
receiptScope: stableReceiptScope,
|
|
235
246
|
source: format.source,
|
|
236
247
|
sourceContentHash: pruned.sourceContentHash,
|
|
237
248
|
visibility: args.visibility,
|
|
@@ -290,7 +301,7 @@ async function runAgentImport(args, agent, context, interactive) {
|
|
|
290
301
|
failed: preparationErrors.length,
|
|
291
302
|
});
|
|
292
303
|
if (!apiKey)
|
|
293
|
-
throw new Error("Set
|
|
304
|
+
throw new Error("Set GROUNDTRACK_IMPORT_KEY or GROUNDTRACK_API_KEY before uploading.");
|
|
294
305
|
if (!args.yes && !interactive)
|
|
295
306
|
throw new Error("Import needs confirmation. Use --yes, or run it in an interactive terminal.");
|
|
296
307
|
if (!args.yes) {
|
|
@@ -13,6 +13,7 @@ export declare function readReceipts(context: SetupEnvironment): ReceiptFile;
|
|
|
13
13
|
export declare function receiptKey(input: {
|
|
14
14
|
apiBaseUrl: string;
|
|
15
15
|
apiKey: string;
|
|
16
|
+
receiptScope?: string;
|
|
16
17
|
source: AgentSessionSource;
|
|
17
18
|
sourceContentHash: string;
|
|
18
19
|
visibility: ImportVisibility;
|
|
@@ -30,7 +30,9 @@ export function receiptKey(input) {
|
|
|
30
30
|
return createHash("sha256")
|
|
31
31
|
.update([
|
|
32
32
|
input.apiBaseUrl,
|
|
33
|
-
|
|
33
|
+
input.receiptScope
|
|
34
|
+
? `scoped:${input.receiptScope}`
|
|
35
|
+
: createHash("sha256").update(input.apiKey).digest("hex"),
|
|
34
36
|
input.source,
|
|
35
37
|
CANONICALIZATION_VERSION,
|
|
36
38
|
input.visibility,
|
|
@@ -16,12 +16,13 @@ function isSensitiveKey(value) {
|
|
|
16
16
|
return sensitiveKeyPattern.test(value.replace(/([a-z0-9])([A-Z])/g, "$1_$2"));
|
|
17
17
|
}
|
|
18
18
|
export function redactCredentialText(value) {
|
|
19
|
+
// Server persistence and CLI normalization both use this redactor.
|
|
19
20
|
return value
|
|
20
21
|
.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED PRIVATE KEY]")
|
|
21
22
|
.replace(/\b(authorization\s*:\s*(?:bearer|basic)\s+)[^\s,;]+/gi, "$1[REDACTED]")
|
|
22
23
|
.replace(/\b((?:[a-z0-9_-]*(?:api[_-]?key|access[_-]?key(?:[_-]?id)?|token|password|passwd|secret|private[_-]?key|credentials?|database[_-]?url))\s*[=:]\s*)[^\s,;]+/gi, "$1[REDACTED]")
|
|
23
24
|
.replace(/(?:^|\s)((?:--)?(?:api-key|token|password|secret)\s+)[^\s,;]+/gi, "$1$2[REDACTED]")
|
|
24
|
-
.replace(/\b(?:sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9]{8,}|github_pat_[A-Za-z0-9_]{8,}|glpat-[A-Za-z0-9_-]{12,}|npm_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{12,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{20,})\b/g, "[REDACTED]")
|
|
25
|
+
.replace(/\b(?:gti_[A-Za-z]{32,}|sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9]{8,}|github_pat_[A-Za-z0-9_]{8,}|glpat-[A-Za-z0-9_-]{12,}|npm_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{12,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{20,})\b/g, "[REDACTED]")
|
|
25
26
|
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[REDACTED]")
|
|
26
27
|
.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi, "$1[REDACTED]@");
|
|
27
28
|
}
|