@astrasyncai/verification-gateway 3.8.0 → 3.10.0
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/dist/adapter-interface/interface.d.mts +3 -2
- package/dist/adapter-interface/interface.d.ts +3 -2
- package/dist/adapters/express.d.mts +3 -2
- package/dist/adapters/express.d.ts +3 -2
- package/dist/adapters/express.js +152 -2
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +152 -2
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/http-pdlss.d.mts +81 -0
- package/dist/adapters/http-pdlss.d.ts +81 -0
- package/dist/adapters/http-pdlss.js +117 -0
- package/dist/adapters/http-pdlss.js.map +1 -0
- package/dist/adapters/http-pdlss.mjs +87 -0
- package/dist/adapters/http-pdlss.mjs.map +1 -0
- package/dist/adapters/mcp.d.mts +2 -1
- package/dist/adapters/mcp.d.ts +2 -1
- package/dist/adapters/mcp.js +2 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +2 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +3 -2
- package/dist/adapters/nextjs.d.ts +3 -2
- package/dist/adapters/nextjs.js +152 -2
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +152 -2
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +3 -2
- package/dist/adapters/sdk.d.ts +3 -2
- package/dist/adapters/sdk.js +2 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +2 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +3 -2
- package/dist/agent/index.d.ts +3 -2
- package/dist/bin/astrasync-claude-hook.js +17 -1
- package/dist/bin/astrasync-guard.js +17 -1
- package/dist/bin/astrasync.js +43 -1
- package/dist/browser/background.js +17 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +17 -1
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +3 -2
- package/dist/browser/browser-adapter.d.ts +3 -2
- package/dist/claude-code/claude-code-adapter.d.mts +3 -2
- package/dist/claude-code/claude-code-adapter.d.ts +3 -2
- package/dist/cli/index.d.mts +3 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cursor/cursor-adapter.d.mts +3 -2
- package/dist/cursor/cursor-adapter.d.ts +3 -2
- package/dist/cursor/extension.d.mts +3 -2
- package/dist/cursor/extension.d.ts +3 -2
- package/dist/cursor/extension.js +17 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +17 -1
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +131 -0
- package/dist/edge-config.d.ts +131 -0
- package/dist/edge-config.js +162 -0
- package/dist/edge-config.js.map +1 -0
- package/dist/edge-config.mjs +131 -0
- package/dist/edge-config.mjs.map +1 -0
- package/dist/{express-C8nJGi5P.d.ts → express-ClNtDhhc.d.ts} +1 -1
- package/dist/{express-Di_hnZZS.d.mts → express-DCXa1oqj.d.mts} +1 -1
- package/dist/gateway/gateway.d.mts +3 -2
- package/dist/gateway/gateway.d.ts +3 -2
- package/dist/gateway/gateway.js +17 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +17 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +3 -2
- package/dist/git-trigger/git-hooks.d.ts +3 -2
- package/dist/{index-CXcvO9Au.d.mts → index-BrNKDmiR.d.mts} +1 -1
- package/dist/{index-CuCkjT7B.d.ts → index-CfHurO1P.d.ts} +1 -1
- package/dist/{index-CBQr4FGs.d.ts → index-D2ztkumS.d.ts} +1 -1
- package/dist/{index-DALAqct7.d.mts → index-Dr_XiN65.d.mts} +1 -1
- package/dist/index.d.mts +27 -82
- package/dist/index.d.ts +27 -82
- package/dist/index.js +435 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +417 -12
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +3 -2
- package/dist/local-evaluator/evaluator.d.ts +3 -2
- package/dist/metadata-capture.d.mts +87 -0
- package/dist/metadata-capture.d.ts +87 -0
- package/dist/metadata-capture.js +184 -0
- package/dist/metadata-capture.js.map +1 -0
- package/dist/metadata-capture.mjs +154 -0
- package/dist/metadata-capture.mjs.map +1 -0
- package/dist/{nextjs-IyXWW2KL.d.ts → nextjs-CEBVBsdi.d.ts} +1 -1
- package/dist/{nextjs-BMAe8ode.d.mts → nextjs-DcQIk6Zj.d.mts} +1 -1
- package/dist/platform-signatures.d.mts +97 -0
- package/dist/platform-signatures.d.ts +97 -0
- package/dist/platform-signatures.js +116 -0
- package/dist/platform-signatures.js.map +1 -0
- package/dist/platform-signatures.mjs +89 -0
- package/dist/platform-signatures.mjs.map +1 -0
- package/dist/{sdk-Cn4KcZ5G.d.mts → sdk-CZkbSOeO.d.mts} +1 -1
- package/dist/{sdk-ThdA_NtL.d.ts → sdk-H0JCLW2y.d.ts} +1 -1
- package/dist/transport/index.d.mts +3 -2
- package/dist/transport/index.d.ts +3 -2
- package/dist/{types-DedAJbNI.d.mts → types-9tns4wyl.d.ts} +88 -1
- package/dist/{types-CSFci5zD.d.mts → types-D0lCtFQ7.d.mts} +1 -1
- package/dist/{types-D1kyMiml.d.ts → types-YbiXYKx1.d.ts} +1 -1
- package/dist/{types-DedAJbNI.d.ts → types-sy3tq8lp.d.mts} +88 -1
- package/dist/ui/index.d.mts +2 -1
- package/dist/ui/index.d.ts +2 -1
- package/dist/verify.d.mts +151 -0
- package/dist/verify.d.ts +151 -0
- package/dist/verify.js +593 -0
- package/dist/verify.js.map +1 -0
- package/dist/verify.mjs +557 -0
- package/dist/verify.mjs.map +1 -0
- package/package.json +26 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { L as LocalPolicy, P as PDLSSContext, V as VerificationDecision, b as LocalPurposeRule } from '../types-
|
|
2
|
-
import '../types-
|
|
1
|
+
import { L as LocalPolicy, P as PDLSSContext, V as VerificationDecision, b as LocalPurposeRule } from '../types-D0lCtFQ7.mjs';
|
|
2
|
+
import '../types-sy3tq8lp.mjs';
|
|
3
|
+
import '../metadata-capture.mjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Local PDLSS Evaluator
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { L as LocalPolicy, P as PDLSSContext, V as VerificationDecision, b as LocalPurposeRule } from '../types-
|
|
2
|
-
import '../types-
|
|
1
|
+
import { L as LocalPolicy, P as PDLSSContext, V as VerificationDecision, b as LocalPurposeRule } from '../types-YbiXYKx1.js';
|
|
2
|
+
import '../types-9tns4wyl.js';
|
|
3
|
+
import '../metadata-capture.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Local PDLSS Evaluator
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximal metadata capture — the shared, edge-safe sanitiser.
|
|
3
|
+
*
|
|
4
|
+
* AstraSync's thesis is total metadata capture: every header and connection
|
|
5
|
+
* signal an inbound agent presents is a signal we want to keep. This module is
|
|
6
|
+
* the ONE place that decides what is safe to store verbatim, what is a secret
|
|
7
|
+
* to drop, and what credential headers reduce to a safe *format prefix* (a
|
|
8
|
+
* platform signal, never the secret itself).
|
|
9
|
+
*
|
|
10
|
+
* It runs in three places that must agree byte-for-byte:
|
|
11
|
+
* - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture
|
|
12
|
+
* point (full CloudFront header arrays),
|
|
13
|
+
* - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,
|
|
14
|
+
* - (indirectly) the backend, which stores whatever the above forward.
|
|
15
|
+
*
|
|
16
|
+
* Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser
|
|
17
|
+
* build, and Deno. Capture is cheap: at the edge and SDK it is local string
|
|
18
|
+
* work, and the backend stores it on a fire-and-forget event insert, so it adds
|
|
19
|
+
* ZERO verify-access decision latency. Detection (which few signals imply which
|
|
20
|
+
* vendor) is a separate, curated concern — see `platform-signatures.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The captured, sanitised view of an inbound agent's request metadata. Attached
|
|
24
|
+
* to verify-access / beacon payloads as `callerMetadata.observedMetadata`.
|
|
25
|
+
*/
|
|
26
|
+
interface ObservedMetadata {
|
|
27
|
+
/** Header name → value, secrets removed, verbatim otherwise. */
|
|
28
|
+
headers: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,
|
|
31
|
+
* `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no
|
|
32
|
+
* credential header was present or none matched a known format.
|
|
33
|
+
*/
|
|
34
|
+
apiKeyFormat?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The subset of `headers` that are known platform-signal headers
|
|
37
|
+
* (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),
|
|
38
|
+
* pulled out for convenient detection + display. Values are the same
|
|
39
|
+
* sanitised strings as in `headers`.
|
|
40
|
+
*/
|
|
41
|
+
platformHeaders?: Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Connection-layer signals the edge can see but the SDK cannot (IP, ASN,
|
|
44
|
+
* country, TLS version/cipher, HTTP version, device class). Populated by the
|
|
45
|
+
* edge adapter's `collectConnectionMetadata`; absent for SDK-only capture.
|
|
46
|
+
*/
|
|
47
|
+
connection?: Record<string, string>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Result of sanitising a raw header map. `headers` is always present (possibly
|
|
51
|
+
* empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.
|
|
52
|
+
*/
|
|
53
|
+
interface SanitizeHeadersResult {
|
|
54
|
+
headers: Record<string, string>;
|
|
55
|
+
apiKeyFormat?: string;
|
|
56
|
+
platformHeaders?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
/** Size caps — the only guard against jsonb bloat from a hostile POST. */
|
|
59
|
+
declare const MAX_HEADERS = 64;
|
|
60
|
+
declare const MAX_HEADER_VALUE_BYTES = 1024;
|
|
61
|
+
declare const MAX_TOTAL_BYTES: number;
|
|
62
|
+
/**
|
|
63
|
+
* Extract the safe key-format prefix from a credential header value. Strips a
|
|
64
|
+
* leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix
|
|
65
|
+
* that the (lowercased) value starts with. Returns undefined for opaque values
|
|
66
|
+
* (e.g. a bare UUID token) so we never guess a format we don't recognise.
|
|
67
|
+
*/
|
|
68
|
+
declare function extractApiKeyFormat(rawValue: string): string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces
|
|
71
|
+
* credential headers to a safe format prefix, keeps everything else verbatim,
|
|
72
|
+
* and enforces the size caps that bound jsonb growth.
|
|
73
|
+
*
|
|
74
|
+
* Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,
|
|
75
|
+
* CloudFront's flattened headers, a plain object). Multi-value headers are
|
|
76
|
+
* joined with `, ` per RFC 7230.
|
|
77
|
+
*/
|
|
78
|
+
declare function sanitizeHeaders(raw: Record<string, string | string[] | undefined> | undefined | null): SanitizeHeadersResult;
|
|
79
|
+
/**
|
|
80
|
+
* Pull the known platform-signal headers out of an ALREADY-sanitised header
|
|
81
|
+
* map. `sanitizeHeaders` already computes this as a by-product; this standalone
|
|
82
|
+
* form is exported for call-sites (edge, tests) that hold a sanitised map and
|
|
83
|
+
* want only the platform subset. Never re-run over raw (unsanitised) headers.
|
|
84
|
+
*/
|
|
85
|
+
declare function extractPlatformHeaders(sanitized: Record<string, string> | undefined | null): Record<string, string>;
|
|
86
|
+
|
|
87
|
+
export { MAX_HEADERS, MAX_HEADER_VALUE_BYTES, MAX_TOTAL_BYTES, type ObservedMetadata, type SanitizeHeadersResult, extractApiKeyFormat, extractPlatformHeaders, sanitizeHeaders };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximal metadata capture — the shared, edge-safe sanitiser.
|
|
3
|
+
*
|
|
4
|
+
* AstraSync's thesis is total metadata capture: every header and connection
|
|
5
|
+
* signal an inbound agent presents is a signal we want to keep. This module is
|
|
6
|
+
* the ONE place that decides what is safe to store verbatim, what is a secret
|
|
7
|
+
* to drop, and what credential headers reduce to a safe *format prefix* (a
|
|
8
|
+
* platform signal, never the secret itself).
|
|
9
|
+
*
|
|
10
|
+
* It runs in three places that must agree byte-for-byte:
|
|
11
|
+
* - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture
|
|
12
|
+
* point (full CloudFront header arrays),
|
|
13
|
+
* - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,
|
|
14
|
+
* - (indirectly) the backend, which stores whatever the above forward.
|
|
15
|
+
*
|
|
16
|
+
* Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser
|
|
17
|
+
* build, and Deno. Capture is cheap: at the edge and SDK it is local string
|
|
18
|
+
* work, and the backend stores it on a fire-and-forget event insert, so it adds
|
|
19
|
+
* ZERO verify-access decision latency. Detection (which few signals imply which
|
|
20
|
+
* vendor) is a separate, curated concern — see `platform-signatures.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The captured, sanitised view of an inbound agent's request metadata. Attached
|
|
24
|
+
* to verify-access / beacon payloads as `callerMetadata.observedMetadata`.
|
|
25
|
+
*/
|
|
26
|
+
interface ObservedMetadata {
|
|
27
|
+
/** Header name → value, secrets removed, verbatim otherwise. */
|
|
28
|
+
headers: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,
|
|
31
|
+
* `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no
|
|
32
|
+
* credential header was present or none matched a known format.
|
|
33
|
+
*/
|
|
34
|
+
apiKeyFormat?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The subset of `headers` that are known platform-signal headers
|
|
37
|
+
* (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),
|
|
38
|
+
* pulled out for convenient detection + display. Values are the same
|
|
39
|
+
* sanitised strings as in `headers`.
|
|
40
|
+
*/
|
|
41
|
+
platformHeaders?: Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Connection-layer signals the edge can see but the SDK cannot (IP, ASN,
|
|
44
|
+
* country, TLS version/cipher, HTTP version, device class). Populated by the
|
|
45
|
+
* edge adapter's `collectConnectionMetadata`; absent for SDK-only capture.
|
|
46
|
+
*/
|
|
47
|
+
connection?: Record<string, string>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Result of sanitising a raw header map. `headers` is always present (possibly
|
|
51
|
+
* empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.
|
|
52
|
+
*/
|
|
53
|
+
interface SanitizeHeadersResult {
|
|
54
|
+
headers: Record<string, string>;
|
|
55
|
+
apiKeyFormat?: string;
|
|
56
|
+
platformHeaders?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
/** Size caps — the only guard against jsonb bloat from a hostile POST. */
|
|
59
|
+
declare const MAX_HEADERS = 64;
|
|
60
|
+
declare const MAX_HEADER_VALUE_BYTES = 1024;
|
|
61
|
+
declare const MAX_TOTAL_BYTES: number;
|
|
62
|
+
/**
|
|
63
|
+
* Extract the safe key-format prefix from a credential header value. Strips a
|
|
64
|
+
* leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix
|
|
65
|
+
* that the (lowercased) value starts with. Returns undefined for opaque values
|
|
66
|
+
* (e.g. a bare UUID token) so we never guess a format we don't recognise.
|
|
67
|
+
*/
|
|
68
|
+
declare function extractApiKeyFormat(rawValue: string): string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces
|
|
71
|
+
* credential headers to a safe format prefix, keeps everything else verbatim,
|
|
72
|
+
* and enforces the size caps that bound jsonb growth.
|
|
73
|
+
*
|
|
74
|
+
* Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,
|
|
75
|
+
* CloudFront's flattened headers, a plain object). Multi-value headers are
|
|
76
|
+
* joined with `, ` per RFC 7230.
|
|
77
|
+
*/
|
|
78
|
+
declare function sanitizeHeaders(raw: Record<string, string | string[] | undefined> | undefined | null): SanitizeHeadersResult;
|
|
79
|
+
/**
|
|
80
|
+
* Pull the known platform-signal headers out of an ALREADY-sanitised header
|
|
81
|
+
* map. `sanitizeHeaders` already computes this as a by-product; this standalone
|
|
82
|
+
* form is exported for call-sites (edge, tests) that hold a sanitised map and
|
|
83
|
+
* want only the platform subset. Never re-run over raw (unsanitised) headers.
|
|
84
|
+
*/
|
|
85
|
+
declare function extractPlatformHeaders(sanitized: Record<string, string> | undefined | null): Record<string, string>;
|
|
86
|
+
|
|
87
|
+
export { MAX_HEADERS, MAX_HEADER_VALUE_BYTES, MAX_TOTAL_BYTES, type ObservedMetadata, type SanitizeHeadersResult, extractApiKeyFormat, extractPlatformHeaders, sanitizeHeaders };
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/metadata-capture.ts
|
|
21
|
+
var metadata_capture_exports = {};
|
|
22
|
+
__export(metadata_capture_exports, {
|
|
23
|
+
MAX_HEADERS: () => MAX_HEADERS,
|
|
24
|
+
MAX_HEADER_VALUE_BYTES: () => MAX_HEADER_VALUE_BYTES,
|
|
25
|
+
MAX_TOTAL_BYTES: () => MAX_TOTAL_BYTES,
|
|
26
|
+
extractApiKeyFormat: () => extractApiKeyFormat,
|
|
27
|
+
extractPlatformHeaders: () => extractPlatformHeaders,
|
|
28
|
+
sanitizeHeaders: () => sanitizeHeaders
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(metadata_capture_exports);
|
|
31
|
+
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
32
|
+
"cookie",
|
|
33
|
+
"set-cookie",
|
|
34
|
+
"x-csrf-token",
|
|
35
|
+
"proxy-authorization",
|
|
36
|
+
"x-astrasync-signature",
|
|
37
|
+
"x-astrasync-secret",
|
|
38
|
+
"x-hub-signature",
|
|
39
|
+
"x-hub-signature-256"
|
|
40
|
+
]);
|
|
41
|
+
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
42
|
+
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
43
|
+
"authorization",
|
|
44
|
+
"x-api-key",
|
|
45
|
+
"x-goog-api-key",
|
|
46
|
+
"api-key"
|
|
47
|
+
]);
|
|
48
|
+
function isSignatureHeader(name) {
|
|
49
|
+
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
50
|
+
}
|
|
51
|
+
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
52
|
+
"openai-organization",
|
|
53
|
+
"openai-project",
|
|
54
|
+
"openai-version",
|
|
55
|
+
"openai-processing-ms",
|
|
56
|
+
"anthropic-version",
|
|
57
|
+
"anthropic-beta",
|
|
58
|
+
"x-goog-user-project",
|
|
59
|
+
"x-goog-api-client",
|
|
60
|
+
"user-agent",
|
|
61
|
+
"x-agent-card-url",
|
|
62
|
+
"x-agent-provider"
|
|
63
|
+
]);
|
|
64
|
+
var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
|
|
65
|
+
var KEY_FORMAT_PREFIXES = [
|
|
66
|
+
"sk-ant-api03",
|
|
67
|
+
"sk-ant-api",
|
|
68
|
+
"sk-ant",
|
|
69
|
+
"sk-proj",
|
|
70
|
+
"sk-svcacct",
|
|
71
|
+
"sk-or-v1",
|
|
72
|
+
"sk-or",
|
|
73
|
+
"sk-lf",
|
|
74
|
+
"sk-",
|
|
75
|
+
"gsk_",
|
|
76
|
+
"aiza",
|
|
77
|
+
"ya29",
|
|
78
|
+
"ghp_",
|
|
79
|
+
"gho_",
|
|
80
|
+
"github_pat_",
|
|
81
|
+
"xai-",
|
|
82
|
+
"pplx-",
|
|
83
|
+
"r8_",
|
|
84
|
+
"hf_",
|
|
85
|
+
"astra-",
|
|
86
|
+
"astrae-"
|
|
87
|
+
];
|
|
88
|
+
var MAX_HEADERS = 64;
|
|
89
|
+
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
90
|
+
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
91
|
+
function byteLength(s) {
|
|
92
|
+
let bytes = 0;
|
|
93
|
+
for (let i = 0; i < s.length; i++) {
|
|
94
|
+
const code = s.charCodeAt(i);
|
|
95
|
+
if (code < 128) bytes += 1;
|
|
96
|
+
else if (code < 2048) bytes += 2;
|
|
97
|
+
else if (code >= 55296 && code <= 56319) {
|
|
98
|
+
bytes += 4;
|
|
99
|
+
i++;
|
|
100
|
+
} else bytes += 3;
|
|
101
|
+
}
|
|
102
|
+
return bytes;
|
|
103
|
+
}
|
|
104
|
+
function extractApiKeyFormat(rawValue) {
|
|
105
|
+
if (!rawValue) return void 0;
|
|
106
|
+
let value = rawValue.trim();
|
|
107
|
+
const spaceIdx = value.indexOf(" ");
|
|
108
|
+
if (spaceIdx > 0) {
|
|
109
|
+
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
110
|
+
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
111
|
+
value = value.slice(spaceIdx + 1).trim();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const lower = value.toLowerCase();
|
|
115
|
+
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
116
|
+
if (lower.startsWith(prefix)) {
|
|
117
|
+
return prefix;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
function isSecretHeader(name) {
|
|
123
|
+
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
124
|
+
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
125
|
+
if (isSignatureHeader(name)) return true;
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
function isPlatformHeader(name) {
|
|
129
|
+
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
130
|
+
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
131
|
+
}
|
|
132
|
+
function sanitizeHeaders(raw) {
|
|
133
|
+
const headers = {};
|
|
134
|
+
const platformHeaders = {};
|
|
135
|
+
let apiKeyFormat;
|
|
136
|
+
let totalBytes = 0;
|
|
137
|
+
let count = 0;
|
|
138
|
+
if (!raw) return { headers };
|
|
139
|
+
for (const rawName of Object.keys(raw)) {
|
|
140
|
+
if (count >= MAX_HEADERS) break;
|
|
141
|
+
const name = rawName.toLowerCase();
|
|
142
|
+
const rawValue = raw[rawName];
|
|
143
|
+
if (rawValue === void 0) continue;
|
|
144
|
+
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
145
|
+
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
146
|
+
const fmt = extractApiKeyFormat(joined);
|
|
147
|
+
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (isSecretHeader(name)) continue;
|
|
151
|
+
let value = joined;
|
|
152
|
+
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
153
|
+
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
154
|
+
}
|
|
155
|
+
const entryBytes = byteLength(name) + byteLength(value);
|
|
156
|
+
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
157
|
+
totalBytes += entryBytes;
|
|
158
|
+
count++;
|
|
159
|
+
headers[name] = value;
|
|
160
|
+
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
161
|
+
}
|
|
162
|
+
const result = { headers };
|
|
163
|
+
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
164
|
+
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
function extractPlatformHeaders(sanitized) {
|
|
168
|
+
const out = {};
|
|
169
|
+
if (!sanitized) return out;
|
|
170
|
+
for (const name of Object.keys(sanitized)) {
|
|
171
|
+
if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
176
|
+
0 && (module.exports = {
|
|
177
|
+
MAX_HEADERS,
|
|
178
|
+
MAX_HEADER_VALUE_BYTES,
|
|
179
|
+
MAX_TOTAL_BYTES,
|
|
180
|
+
extractApiKeyFormat,
|
|
181
|
+
extractPlatformHeaders,
|
|
182
|
+
sanitizeHeaders
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=metadata-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/metadata-capture.ts"],"sourcesContent":["/**\n * Maximal metadata capture — the shared, edge-safe sanitiser.\n *\n * AstraSync's thesis is total metadata capture: every header and connection\n * signal an inbound agent presents is a signal we want to keep. This module is\n * the ONE place that decides what is safe to store verbatim, what is a secret\n * to drop, and what credential headers reduce to a safe *format prefix* (a\n * platform signal, never the secret itself).\n *\n * It runs in three places that must agree byte-for-byte:\n * - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture\n * point (full CloudFront header arrays),\n * - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,\n * - (indirectly) the backend, which stores whatever the above forward.\n *\n * Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser\n * build, and Deno. Capture is cheap: at the edge and SDK it is local string\n * work, and the backend stores it on a fire-and-forget event insert, so it adds\n * ZERO verify-access decision latency. Detection (which few signals imply which\n * vendor) is a separate, curated concern — see `platform-signatures.ts`.\n */\n\n/**\n * The captured, sanitised view of an inbound agent's request metadata. Attached\n * to verify-access / beacon payloads as `callerMetadata.observedMetadata`.\n */\nexport interface ObservedMetadata {\n /** Header name → value, secrets removed, verbatim otherwise. */\n headers: Record<string, string>;\n /**\n * Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,\n * `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no\n * credential header was present or none matched a known format.\n */\n apiKeyFormat?: string;\n /**\n * The subset of `headers` that are known platform-signal headers\n * (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),\n * pulled out for convenient detection + display. Values are the same\n * sanitised strings as in `headers`.\n */\n platformHeaders?: Record<string, string>;\n /**\n * Connection-layer signals the edge can see but the SDK cannot (IP, ASN,\n * country, TLS version/cipher, HTTP version, device class). Populated by the\n * edge adapter's `collectConnectionMetadata`; absent for SDK-only capture.\n */\n connection?: Record<string, string>;\n}\n\n/**\n * Result of sanitising a raw header map. `headers` is always present (possibly\n * empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.\n */\nexport interface SanitizeHeadersResult {\n headers: Record<string, string>;\n apiKeyFormat?: string;\n platformHeaders?: Record<string, string>;\n}\n\n/**\n * Header names dropped entirely — genuine secrets or our own credentials that\n * describe the request's transport, not the agent. Matched case-insensitively\n * on the exact header name.\n */\nconst SECRET_HEADER_NAMES = new Set([\n 'cookie',\n 'set-cookie',\n 'x-csrf-token',\n 'proxy-authorization',\n 'x-astrasync-signature',\n 'x-astrasync-secret',\n 'x-hub-signature',\n 'x-hub-signature-256',\n]);\n\n/**\n * Header-name prefixes dropped entirely — our own credential / signing surface\n * (`x-astrasync-*`, `kya-*`) must never round-trip into stored metadata.\n */\nconst SECRET_HEADER_PREFIXES = ['x-astrasync-', 'kya-', 'kya_'];\n\n/**\n * Credential headers whose VALUE is a secret but whose FORMAT is a signal. We\n * keep the leading format prefix (up to the random tail) and drop the rest.\n */\nconst CREDENTIAL_HEADER_NAMES = new Set([\n 'authorization',\n 'x-api-key',\n 'x-goog-api-key',\n 'api-key',\n]);\n\n/**\n * Header names that carry a raw signature value (drop the value; the presence\n * is not worth a bloat risk). Matched as a suffix so `x-*-signature` variants\n * are covered without an exhaustive list.\n */\nfunction isSignatureHeader(name: string): boolean {\n return name === 'signature' || name.endsWith('-signature') || name.endsWith('-signature-256');\n}\n\n/**\n * Known platform-signal headers — pulled into `platformHeaders` for convenient\n * detection + display. Exact names plus a few prefixes (`x-goog-`,\n * `x-stainless-` — the OpenAI/Anthropic SDK client fingerprint headers).\n */\nconst PLATFORM_HEADER_NAMES = new Set([\n 'openai-organization',\n 'openai-project',\n 'openai-version',\n 'openai-processing-ms',\n 'anthropic-version',\n 'anthropic-beta',\n 'x-goog-user-project',\n 'x-goog-api-client',\n 'user-agent',\n 'x-agent-card-url',\n 'x-agent-provider',\n]);\nconst PLATFORM_HEADER_PREFIXES = ['x-goog-', 'x-stainless-', 'x-anthropic-', 'x-openai-'];\n\n/**\n * Known API-key format prefixes, longest-first so `sk-ant-api03` wins over\n * `sk-ant` and `sk-`. Each is the SAFE, non-secret leading token of a\n * credential; the random tail is never captured.\n */\nconst KEY_FORMAT_PREFIXES = [\n 'sk-ant-api03',\n 'sk-ant-api',\n 'sk-ant',\n 'sk-proj',\n 'sk-svcacct',\n 'sk-or-v1',\n 'sk-or',\n 'sk-lf',\n 'sk-',\n 'gsk_',\n 'aiza',\n 'ya29',\n 'ghp_',\n 'gho_',\n 'github_pat_',\n 'xai-',\n 'pplx-',\n 'r8_',\n 'hf_',\n 'astra-',\n 'astrae-',\n];\n\n/** Size caps — the only guard against jsonb bloat from a hostile POST. */\nexport const MAX_HEADERS = 64;\nexport const MAX_HEADER_VALUE_BYTES = 1024;\nexport const MAX_TOTAL_BYTES = 16 * 1024;\n\nfunction byteLength(s: string): number {\n // Edge-safe (no Buffer): count UTF-8 bytes without allocating a Buffer.\n let bytes = 0;\n for (let i = 0; i < s.length; i++) {\n const code = s.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++; // surrogate pair\n } else bytes += 3;\n }\n return bytes;\n}\n\n/**\n * Extract the safe key-format prefix from a credential header value. Strips a\n * leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix\n * that the (lowercased) value starts with. Returns undefined for opaque values\n * (e.g. a bare UUID token) so we never guess a format we don't recognise.\n */\nexport function extractApiKeyFormat(rawValue: string): string | undefined {\n if (!rawValue) return undefined;\n let value = rawValue.trim();\n const spaceIdx = value.indexOf(' ');\n if (spaceIdx > 0) {\n const scheme = value.slice(0, spaceIdx).toLowerCase();\n if (scheme === 'bearer' || scheme === 'basic' || scheme === 'token') {\n value = value.slice(spaceIdx + 1).trim();\n }\n }\n const lower = value.toLowerCase();\n for (const prefix of KEY_FORMAT_PREFIXES) {\n if (lower.startsWith(prefix)) {\n // Return the prefix as-declared in the list (canonical casing).\n return prefix;\n }\n }\n return undefined;\n}\n\nfunction isSecretHeader(name: string): boolean {\n if (SECRET_HEADER_NAMES.has(name)) return true;\n if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;\n if (isSignatureHeader(name)) return true;\n return false;\n}\n\nfunction isPlatformHeader(name: string): boolean {\n if (PLATFORM_HEADER_NAMES.has(name)) return true;\n return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));\n}\n\n/**\n * Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces\n * credential headers to a safe format prefix, keeps everything else verbatim,\n * and enforces the size caps that bound jsonb growth.\n *\n * Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,\n * CloudFront's flattened headers, a plain object). Multi-value headers are\n * joined with `, ` per RFC 7230.\n */\nexport function sanitizeHeaders(\n raw: Record<string, string | string[] | undefined> | undefined | null\n): SanitizeHeadersResult {\n const headers: Record<string, string> = {};\n const platformHeaders: Record<string, string> = {};\n let apiKeyFormat: string | undefined;\n let totalBytes = 0;\n let count = 0;\n\n if (!raw) return { headers };\n\n for (const rawName of Object.keys(raw)) {\n if (count >= MAX_HEADERS) break;\n const name = rawName.toLowerCase();\n const rawValue = raw[rawName];\n if (rawValue === undefined) continue;\n const joined = Array.isArray(rawValue) ? rawValue.join(', ') : String(rawValue);\n\n // Credential headers: capture the format prefix, drop the secret.\n if (CREDENTIAL_HEADER_NAMES.has(name)) {\n const fmt = extractApiKeyFormat(joined);\n if (fmt && !apiKeyFormat) apiKeyFormat = fmt;\n continue;\n }\n\n // Genuine secrets: drop entirely.\n if (isSecretHeader(name)) continue;\n\n // Everything else describing the agent: keep, bounded.\n let value = joined;\n if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {\n value = value.slice(0, MAX_HEADER_VALUE_BYTES);\n }\n const entryBytes = byteLength(name) + byteLength(value);\n if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;\n totalBytes += entryBytes;\n count++;\n headers[name] = value;\n if (isPlatformHeader(name)) platformHeaders[name] = value;\n }\n\n const result: SanitizeHeadersResult = { headers };\n if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;\n if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;\n return result;\n}\n\n/**\n * Pull the known platform-signal headers out of an ALREADY-sanitised header\n * map. `sanitizeHeaders` already computes this as a by-product; this standalone\n * form is exported for call-sites (edge, tests) that hold a sanitised map and\n * want only the platform subset. Never re-run over raw (unsanitised) headers.\n */\nexport function extractPlatformHeaders(\n sanitized: Record<string, string> | undefined | null\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!sanitized) return out;\n for (const name of Object.keys(sanitized)) {\n if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];\n }\n return out;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/metadata-capture.ts
|
|
2
|
+
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
3
|
+
"cookie",
|
|
4
|
+
"set-cookie",
|
|
5
|
+
"x-csrf-token",
|
|
6
|
+
"proxy-authorization",
|
|
7
|
+
"x-astrasync-signature",
|
|
8
|
+
"x-astrasync-secret",
|
|
9
|
+
"x-hub-signature",
|
|
10
|
+
"x-hub-signature-256"
|
|
11
|
+
]);
|
|
12
|
+
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
13
|
+
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
14
|
+
"authorization",
|
|
15
|
+
"x-api-key",
|
|
16
|
+
"x-goog-api-key",
|
|
17
|
+
"api-key"
|
|
18
|
+
]);
|
|
19
|
+
function isSignatureHeader(name) {
|
|
20
|
+
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
21
|
+
}
|
|
22
|
+
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
23
|
+
"openai-organization",
|
|
24
|
+
"openai-project",
|
|
25
|
+
"openai-version",
|
|
26
|
+
"openai-processing-ms",
|
|
27
|
+
"anthropic-version",
|
|
28
|
+
"anthropic-beta",
|
|
29
|
+
"x-goog-user-project",
|
|
30
|
+
"x-goog-api-client",
|
|
31
|
+
"user-agent",
|
|
32
|
+
"x-agent-card-url",
|
|
33
|
+
"x-agent-provider"
|
|
34
|
+
]);
|
|
35
|
+
var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
|
|
36
|
+
var KEY_FORMAT_PREFIXES = [
|
|
37
|
+
"sk-ant-api03",
|
|
38
|
+
"sk-ant-api",
|
|
39
|
+
"sk-ant",
|
|
40
|
+
"sk-proj",
|
|
41
|
+
"sk-svcacct",
|
|
42
|
+
"sk-or-v1",
|
|
43
|
+
"sk-or",
|
|
44
|
+
"sk-lf",
|
|
45
|
+
"sk-",
|
|
46
|
+
"gsk_",
|
|
47
|
+
"aiza",
|
|
48
|
+
"ya29",
|
|
49
|
+
"ghp_",
|
|
50
|
+
"gho_",
|
|
51
|
+
"github_pat_",
|
|
52
|
+
"xai-",
|
|
53
|
+
"pplx-",
|
|
54
|
+
"r8_",
|
|
55
|
+
"hf_",
|
|
56
|
+
"astra-",
|
|
57
|
+
"astrae-"
|
|
58
|
+
];
|
|
59
|
+
var MAX_HEADERS = 64;
|
|
60
|
+
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
61
|
+
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
62
|
+
function byteLength(s) {
|
|
63
|
+
let bytes = 0;
|
|
64
|
+
for (let i = 0; i < s.length; i++) {
|
|
65
|
+
const code = s.charCodeAt(i);
|
|
66
|
+
if (code < 128) bytes += 1;
|
|
67
|
+
else if (code < 2048) bytes += 2;
|
|
68
|
+
else if (code >= 55296 && code <= 56319) {
|
|
69
|
+
bytes += 4;
|
|
70
|
+
i++;
|
|
71
|
+
} else bytes += 3;
|
|
72
|
+
}
|
|
73
|
+
return bytes;
|
|
74
|
+
}
|
|
75
|
+
function extractApiKeyFormat(rawValue) {
|
|
76
|
+
if (!rawValue) return void 0;
|
|
77
|
+
let value = rawValue.trim();
|
|
78
|
+
const spaceIdx = value.indexOf(" ");
|
|
79
|
+
if (spaceIdx > 0) {
|
|
80
|
+
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
81
|
+
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
82
|
+
value = value.slice(spaceIdx + 1).trim();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const lower = value.toLowerCase();
|
|
86
|
+
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
87
|
+
if (lower.startsWith(prefix)) {
|
|
88
|
+
return prefix;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
function isSecretHeader(name) {
|
|
94
|
+
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
95
|
+
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
96
|
+
if (isSignatureHeader(name)) return true;
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
function isPlatformHeader(name) {
|
|
100
|
+
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
101
|
+
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
102
|
+
}
|
|
103
|
+
function sanitizeHeaders(raw) {
|
|
104
|
+
const headers = {};
|
|
105
|
+
const platformHeaders = {};
|
|
106
|
+
let apiKeyFormat;
|
|
107
|
+
let totalBytes = 0;
|
|
108
|
+
let count = 0;
|
|
109
|
+
if (!raw) return { headers };
|
|
110
|
+
for (const rawName of Object.keys(raw)) {
|
|
111
|
+
if (count >= MAX_HEADERS) break;
|
|
112
|
+
const name = rawName.toLowerCase();
|
|
113
|
+
const rawValue = raw[rawName];
|
|
114
|
+
if (rawValue === void 0) continue;
|
|
115
|
+
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
116
|
+
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
117
|
+
const fmt = extractApiKeyFormat(joined);
|
|
118
|
+
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (isSecretHeader(name)) continue;
|
|
122
|
+
let value = joined;
|
|
123
|
+
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
124
|
+
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
125
|
+
}
|
|
126
|
+
const entryBytes = byteLength(name) + byteLength(value);
|
|
127
|
+
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
128
|
+
totalBytes += entryBytes;
|
|
129
|
+
count++;
|
|
130
|
+
headers[name] = value;
|
|
131
|
+
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
132
|
+
}
|
|
133
|
+
const result = { headers };
|
|
134
|
+
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
135
|
+
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
function extractPlatformHeaders(sanitized) {
|
|
139
|
+
const out = {};
|
|
140
|
+
if (!sanitized) return out;
|
|
141
|
+
for (const name of Object.keys(sanitized)) {
|
|
142
|
+
if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
MAX_HEADERS,
|
|
148
|
+
MAX_HEADER_VALUE_BYTES,
|
|
149
|
+
MAX_TOTAL_BYTES,
|
|
150
|
+
extractApiKeyFormat,
|
|
151
|
+
extractPlatformHeaders,
|
|
152
|
+
sanitizeHeaders
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=metadata-capture.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/metadata-capture.ts"],"sourcesContent":["/**\n * Maximal metadata capture — the shared, edge-safe sanitiser.\n *\n * AstraSync's thesis is total metadata capture: every header and connection\n * signal an inbound agent presents is a signal we want to keep. This module is\n * the ONE place that decides what is safe to store verbatim, what is a secret\n * to drop, and what credential headers reduce to a safe *format prefix* (a\n * platform signal, never the secret itself).\n *\n * It runs in three places that must agree byte-for-byte:\n * - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture\n * point (full CloudFront header arrays),\n * - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,\n * - (indirectly) the backend, which stores whatever the above forward.\n *\n * Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser\n * build, and Deno. Capture is cheap: at the edge and SDK it is local string\n * work, and the backend stores it on a fire-and-forget event insert, so it adds\n * ZERO verify-access decision latency. Detection (which few signals imply which\n * vendor) is a separate, curated concern — see `platform-signatures.ts`.\n */\n\n/**\n * The captured, sanitised view of an inbound agent's request metadata. Attached\n * to verify-access / beacon payloads as `callerMetadata.observedMetadata`.\n */\nexport interface ObservedMetadata {\n /** Header name → value, secrets removed, verbatim otherwise. */\n headers: Record<string, string>;\n /**\n * Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,\n * `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no\n * credential header was present or none matched a known format.\n */\n apiKeyFormat?: string;\n /**\n * The subset of `headers` that are known platform-signal headers\n * (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),\n * pulled out for convenient detection + display. Values are the same\n * sanitised strings as in `headers`.\n */\n platformHeaders?: Record<string, string>;\n /**\n * Connection-layer signals the edge can see but the SDK cannot (IP, ASN,\n * country, TLS version/cipher, HTTP version, device class). Populated by the\n * edge adapter's `collectConnectionMetadata`; absent for SDK-only capture.\n */\n connection?: Record<string, string>;\n}\n\n/**\n * Result of sanitising a raw header map. `headers` is always present (possibly\n * empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.\n */\nexport interface SanitizeHeadersResult {\n headers: Record<string, string>;\n apiKeyFormat?: string;\n platformHeaders?: Record<string, string>;\n}\n\n/**\n * Header names dropped entirely — genuine secrets or our own credentials that\n * describe the request's transport, not the agent. Matched case-insensitively\n * on the exact header name.\n */\nconst SECRET_HEADER_NAMES = new Set([\n 'cookie',\n 'set-cookie',\n 'x-csrf-token',\n 'proxy-authorization',\n 'x-astrasync-signature',\n 'x-astrasync-secret',\n 'x-hub-signature',\n 'x-hub-signature-256',\n]);\n\n/**\n * Header-name prefixes dropped entirely — our own credential / signing surface\n * (`x-astrasync-*`, `kya-*`) must never round-trip into stored metadata.\n */\nconst SECRET_HEADER_PREFIXES = ['x-astrasync-', 'kya-', 'kya_'];\n\n/**\n * Credential headers whose VALUE is a secret but whose FORMAT is a signal. We\n * keep the leading format prefix (up to the random tail) and drop the rest.\n */\nconst CREDENTIAL_HEADER_NAMES = new Set([\n 'authorization',\n 'x-api-key',\n 'x-goog-api-key',\n 'api-key',\n]);\n\n/**\n * Header names that carry a raw signature value (drop the value; the presence\n * is not worth a bloat risk). Matched as a suffix so `x-*-signature` variants\n * are covered without an exhaustive list.\n */\nfunction isSignatureHeader(name: string): boolean {\n return name === 'signature' || name.endsWith('-signature') || name.endsWith('-signature-256');\n}\n\n/**\n * Known platform-signal headers — pulled into `platformHeaders` for convenient\n * detection + display. Exact names plus a few prefixes (`x-goog-`,\n * `x-stainless-` — the OpenAI/Anthropic SDK client fingerprint headers).\n */\nconst PLATFORM_HEADER_NAMES = new Set([\n 'openai-organization',\n 'openai-project',\n 'openai-version',\n 'openai-processing-ms',\n 'anthropic-version',\n 'anthropic-beta',\n 'x-goog-user-project',\n 'x-goog-api-client',\n 'user-agent',\n 'x-agent-card-url',\n 'x-agent-provider',\n]);\nconst PLATFORM_HEADER_PREFIXES = ['x-goog-', 'x-stainless-', 'x-anthropic-', 'x-openai-'];\n\n/**\n * Known API-key format prefixes, longest-first so `sk-ant-api03` wins over\n * `sk-ant` and `sk-`. Each is the SAFE, non-secret leading token of a\n * credential; the random tail is never captured.\n */\nconst KEY_FORMAT_PREFIXES = [\n 'sk-ant-api03',\n 'sk-ant-api',\n 'sk-ant',\n 'sk-proj',\n 'sk-svcacct',\n 'sk-or-v1',\n 'sk-or',\n 'sk-lf',\n 'sk-',\n 'gsk_',\n 'aiza',\n 'ya29',\n 'ghp_',\n 'gho_',\n 'github_pat_',\n 'xai-',\n 'pplx-',\n 'r8_',\n 'hf_',\n 'astra-',\n 'astrae-',\n];\n\n/** Size caps — the only guard against jsonb bloat from a hostile POST. */\nexport const MAX_HEADERS = 64;\nexport const MAX_HEADER_VALUE_BYTES = 1024;\nexport const MAX_TOTAL_BYTES = 16 * 1024;\n\nfunction byteLength(s: string): number {\n // Edge-safe (no Buffer): count UTF-8 bytes without allocating a Buffer.\n let bytes = 0;\n for (let i = 0; i < s.length; i++) {\n const code = s.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++; // surrogate pair\n } else bytes += 3;\n }\n return bytes;\n}\n\n/**\n * Extract the safe key-format prefix from a credential header value. Strips a\n * leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix\n * that the (lowercased) value starts with. Returns undefined for opaque values\n * (e.g. a bare UUID token) so we never guess a format we don't recognise.\n */\nexport function extractApiKeyFormat(rawValue: string): string | undefined {\n if (!rawValue) return undefined;\n let value = rawValue.trim();\n const spaceIdx = value.indexOf(' ');\n if (spaceIdx > 0) {\n const scheme = value.slice(0, spaceIdx).toLowerCase();\n if (scheme === 'bearer' || scheme === 'basic' || scheme === 'token') {\n value = value.slice(spaceIdx + 1).trim();\n }\n }\n const lower = value.toLowerCase();\n for (const prefix of KEY_FORMAT_PREFIXES) {\n if (lower.startsWith(prefix)) {\n // Return the prefix as-declared in the list (canonical casing).\n return prefix;\n }\n }\n return undefined;\n}\n\nfunction isSecretHeader(name: string): boolean {\n if (SECRET_HEADER_NAMES.has(name)) return true;\n if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;\n if (isSignatureHeader(name)) return true;\n return false;\n}\n\nfunction isPlatformHeader(name: string): boolean {\n if (PLATFORM_HEADER_NAMES.has(name)) return true;\n return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));\n}\n\n/**\n * Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces\n * credential headers to a safe format prefix, keeps everything else verbatim,\n * and enforces the size caps that bound jsonb growth.\n *\n * Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,\n * CloudFront's flattened headers, a plain object). Multi-value headers are\n * joined with `, ` per RFC 7230.\n */\nexport function sanitizeHeaders(\n raw: Record<string, string | string[] | undefined> | undefined | null\n): SanitizeHeadersResult {\n const headers: Record<string, string> = {};\n const platformHeaders: Record<string, string> = {};\n let apiKeyFormat: string | undefined;\n let totalBytes = 0;\n let count = 0;\n\n if (!raw) return { headers };\n\n for (const rawName of Object.keys(raw)) {\n if (count >= MAX_HEADERS) break;\n const name = rawName.toLowerCase();\n const rawValue = raw[rawName];\n if (rawValue === undefined) continue;\n const joined = Array.isArray(rawValue) ? rawValue.join(', ') : String(rawValue);\n\n // Credential headers: capture the format prefix, drop the secret.\n if (CREDENTIAL_HEADER_NAMES.has(name)) {\n const fmt = extractApiKeyFormat(joined);\n if (fmt && !apiKeyFormat) apiKeyFormat = fmt;\n continue;\n }\n\n // Genuine secrets: drop entirely.\n if (isSecretHeader(name)) continue;\n\n // Everything else describing the agent: keep, bounded.\n let value = joined;\n if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {\n value = value.slice(0, MAX_HEADER_VALUE_BYTES);\n }\n const entryBytes = byteLength(name) + byteLength(value);\n if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;\n totalBytes += entryBytes;\n count++;\n headers[name] = value;\n if (isPlatformHeader(name)) platformHeaders[name] = value;\n }\n\n const result: SanitizeHeadersResult = { headers };\n if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;\n if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;\n return result;\n}\n\n/**\n * Pull the known platform-signal headers out of an ALREADY-sanitised header\n * map. `sanitizeHeaders` already computes this as a by-product; this standalone\n * form is exported for call-sites (edge, tests) that hold a sanitised map and\n * want only the platform subset. Never re-run over raw (unsanitised) headers.\n */\nexport function extractPlatformHeaders(\n sanitized: Record<string, string> | undefined | null\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!sanitized) return out;\n for (const name of Object.keys(sanitized)) {\n if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];\n }\n return out;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import { N as NextJsMiddlewareOptions } from './types-
|
|
3
|
+
import { N as NextJsMiddlewareOptions } from './types-9tns4wyl.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Create Next.js middleware for agent verification.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import { N as NextJsMiddlewareOptions } from './types-
|
|
3
|
+
import { N as NextJsMiddlewareOptions } from './types-sy3tq8lp.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Create Next.js middleware for agent verification.
|