@tangle-network/cli-agent-registry 0.0.0-stage → 0.14.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/LICENSE +11 -0
- package/README.md +145 -2
- package/dist/backend-types-CJH-wHS3.d.mts +56 -0
- package/dist/backend-types-CREj4iOY.mjs +45 -0
- package/dist/backend-types.d.mts +2 -0
- package/dist/backend-types.mjs +2 -0
- package/dist/cli-auth-bundle.d.mts +49 -0
- package/dist/cli-auth-bundle.mjs +92 -0
- package/dist/cli-auth-placeholder.d.mts +54 -0
- package/dist/cli-auth-placeholder.mjs +200 -0
- package/dist/cli-backend-auth-env.d.mts +6 -0
- package/dist/cli-backend-auth-env.mjs +44 -0
- package/dist/default-backend.d.mts +24 -0
- package/dist/default-backend.mjs +31 -0
- package/dist/harness-DIdVNSwl.mjs +167 -0
- package/dist/index.d.mts +1400 -0
- package/dist/index.mjs +146 -0
- package/dist/local-cli-auth.d.mts +14 -0
- package/dist/local-cli-auth.mjs +31 -0
- package/dist/native-session-contracts-DWFzgoye.mjs +1162 -0
- package/dist/native-session-contracts.d.mts +354 -0
- package/dist/native-session-contracts.mjs +2 -0
- package/dist/servable-models.d.mts +104 -0
- package/dist/servable-models.mjs +147 -0
- package/dist/session-contract-BC75JdnA.d.mts +131 -0
- package/dist/session-contract.d.mts +2 -0
- package/dist/session-contract.mjs +190 -0
- package/dist/specs-BSELpX1h.d.mts +415 -0
- package/dist/specs-Bbiay_8K.mjs +704 -0
- package/dist/specs.d.mts +3 -0
- package/dist/specs.mjs +3 -0
- package/package.json +81 -3
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/cli-backend-auth-env.d.ts
|
|
2
|
+
/** The narrow credential leg shared by the host and sidecar rebind boundary. */
|
|
3
|
+
declare function assertCliBackendAuthEnv(backendType: string | undefined, authEnv: Readonly<Record<string, string>>): void;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { assertCliBackendAuthEnv };
|
|
6
|
+
//# sourceMappingURL=cli-backend-auth-env.d.mts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { l as getSpec } from "./specs-Bbiay_8K.mjs";
|
|
2
|
+
import { CLI_AUTH_REFERENCE_ENV_VAR, cliAuthFilesSchema, cliAuthReferenceSchema, resolveCliAuthReference } from "./cli-auth-bundle.mjs";
|
|
3
|
+
import { n as isSafeEnvVarName, t as isForbiddenEnvVarName } from "./harness-DIdVNSwl.mjs";
|
|
4
|
+
//#region src/cli-backend-auth-env.ts
|
|
5
|
+
/** The narrow credential leg shared by the host and sidecar rebind boundary. */
|
|
6
|
+
function assertCliBackendAuthEnv(backendType, authEnv) {
|
|
7
|
+
if (Object.keys(authEnv).length === 0) return;
|
|
8
|
+
const spec = backendType ? getSpec(backendType) : void 0;
|
|
9
|
+
if (!spec) throw new Error("Credential delivery requires a registered backend");
|
|
10
|
+
const allowed = new Set([
|
|
11
|
+
spec.envVars.apiKey,
|
|
12
|
+
spec.envVars.oauthToken,
|
|
13
|
+
spec.envVars.authFiles
|
|
14
|
+
].filter((name) => name !== void 0));
|
|
15
|
+
const rawReference = authEnv[CLI_AUTH_REFERENCE_ENV_VAR];
|
|
16
|
+
if (rawReference !== void 0) {
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(rawReference);
|
|
20
|
+
} catch {
|
|
21
|
+
throw new Error("Invalid native credential reference");
|
|
22
|
+
}
|
|
23
|
+
const result = cliAuthReferenceSchema.safeParse(parsed);
|
|
24
|
+
if (!result.success || !isSafeEnvVarName(result.data.secretEnv) || isForbiddenEnvVarName(result.data.secretEnv)) throw new Error("Invalid native credential reference");
|
|
25
|
+
allowed.add(CLI_AUTH_REFERENCE_ENV_VAR);
|
|
26
|
+
allowed.add(result.data.secretEnv);
|
|
27
|
+
resolveCliAuthReference(spec.name, { cliAuth: result.data }, authEnv);
|
|
28
|
+
}
|
|
29
|
+
for (const [name, value] of Object.entries(authEnv)) if (!allowed.has(name) || value.includes("\0")) throw new Error("Invalid backend credential environment");
|
|
30
|
+
const files = spec.envVars.authFiles && authEnv[spec.envVars.authFiles];
|
|
31
|
+
if (files !== void 0 && files !== "") {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = JSON.parse(files);
|
|
35
|
+
} catch {
|
|
36
|
+
throw new Error("Invalid backend auth files");
|
|
37
|
+
}
|
|
38
|
+
if (!(Array.isArray(parsed) && parsed.length === 0) && !cliAuthFilesSchema.safeParse(parsed).success) throw new Error("Invalid backend auth files");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { assertCliBackendAuthEnv };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=cli-backend-auth-env.mjs.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { r as BackendType } from "./backend-types-CJH-wHS3.mjs";
|
|
2
|
+
//#region src/default-backend.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Platform-wide default agent backend, read from `DEFAULT_AGENT_BACKEND`.
|
|
5
|
+
*
|
|
6
|
+
* Every "no backend type was supplied" path resolves
|
|
7
|
+
* through — request bodies, container labels, session records, env-driven
|
|
8
|
+
* boot. Deployment config (env files, Dockerfile ENV, test setup) names the
|
|
9
|
+
* default exactly once; code never carries a vendor literal.
|
|
10
|
+
*
|
|
11
|
+
* Fail-closed: throws when the variable is unset or names an unregistered
|
|
12
|
+
* backend. A silent literal here would weld one vendor backend into the
|
|
13
|
+
* platform and mask misconfigured deployments.
|
|
14
|
+
*
|
|
15
|
+
* Published as its own `./default-backend` entry: it pulls only `./specs.js`
|
|
16
|
+
* (data-only), so Cloudflare Worker / edge bundles can consume it without the
|
|
17
|
+
* Node-only barrel (adapter bindings, local CLI auth). Workers have no
|
|
18
|
+
* `process.env` — they MUST pass their bindings record explicitly; the
|
|
19
|
+
* `process.env` default only fires when the argument is omitted.
|
|
20
|
+
*/
|
|
21
|
+
declare function resolveDefaultBackend(env?: Record<string, string | undefined>): BackendType;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { resolveDefaultBackend };
|
|
24
|
+
//# sourceMappingURL=default-backend.d.mts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { i as isBackendType, t as ALL_BACKEND_TYPES } from "./backend-types-CREj4iOY.mjs";
|
|
2
|
+
import "./specs-Bbiay_8K.mjs";
|
|
3
|
+
//#region src/default-backend.ts
|
|
4
|
+
/**
|
|
5
|
+
* Platform-wide default agent backend, read from `DEFAULT_AGENT_BACKEND`.
|
|
6
|
+
*
|
|
7
|
+
* Every "no backend type was supplied" path resolves
|
|
8
|
+
* through — request bodies, container labels, session records, env-driven
|
|
9
|
+
* boot. Deployment config (env files, Dockerfile ENV, test setup) names the
|
|
10
|
+
* default exactly once; code never carries a vendor literal.
|
|
11
|
+
*
|
|
12
|
+
* Fail-closed: throws when the variable is unset or names an unregistered
|
|
13
|
+
* backend. A silent literal here would weld one vendor backend into the
|
|
14
|
+
* platform and mask misconfigured deployments.
|
|
15
|
+
*
|
|
16
|
+
* Published as its own `./default-backend` entry: it pulls only `./specs.js`
|
|
17
|
+
* (data-only), so Cloudflare Worker / edge bundles can consume it without the
|
|
18
|
+
* Node-only barrel (adapter bindings, local CLI auth). Workers have no
|
|
19
|
+
* `process.env` — they MUST pass their bindings record explicitly; the
|
|
20
|
+
* `process.env` default only fires when the argument is omitted.
|
|
21
|
+
*/
|
|
22
|
+
function resolveDefaultBackend(env = process.env) {
|
|
23
|
+
const raw = env.DEFAULT_AGENT_BACKEND;
|
|
24
|
+
if (raw === void 0 || raw === "") throw new Error(`DEFAULT_AGENT_BACKEND is not set. A backend type was omitted and no platform default is configured. Set DEFAULT_AGENT_BACKEND to one of: ${ALL_BACKEND_TYPES.join(", ")}`);
|
|
25
|
+
if (!isBackendType(raw)) throw new Error(`DEFAULT_AGENT_BACKEND="${raw}" is not a registered backend. Registered backends: ${ALL_BACKEND_TYPES.join(", ")}`);
|
|
26
|
+
return raw;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { resolveDefaultBackend };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=default-backend.mjs.map
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { o as HARNESS_WARM_TRANSPORT_ENV } from "./native-session-contracts-DWFzgoye.mjs";
|
|
2
|
+
import "./backend-types-CREj4iOY.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Strip the per-sandbox salt, returning the shared base token. The reverse
|
|
6
|
+
* lookup (token -> secret env var name) keys on the base, so a salted token must
|
|
7
|
+
* be reduced here before lookup. An unsalted token (no separator) is returned
|
|
8
|
+
* as-is.
|
|
9
|
+
*/
|
|
10
|
+
function baseProxyToken(token) {
|
|
11
|
+
const i = token.indexOf(".");
|
|
12
|
+
return i === -1 ? token : token.slice(0, i);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The dummy model credential the egress proxy swaps for each env var a box
|
|
16
|
+
* may carry. A box holds only these, salted per sandbox; the real keys stay
|
|
17
|
+
* with the egress proxy. Host-side proxy configuration adds the non-model
|
|
18
|
+
* tokens.
|
|
19
|
+
*/
|
|
20
|
+
const MODEL_PROXY_TOKENS = {
|
|
21
|
+
OPENCODE_MODEL_API_KEY: "proxy-model-token",
|
|
22
|
+
OPENAI_API_KEY: "proxy-openai-token",
|
|
23
|
+
ANTHROPIC_API_KEY: "proxy-anthropic-token",
|
|
24
|
+
OPENROUTER_API_KEY: "proxy-openrouter-token",
|
|
25
|
+
TANGLE_INFERENCE_KEY: "proxy-openai-token",
|
|
26
|
+
ZAI_API_KEY: "proxy-zai-token",
|
|
27
|
+
ZHIPU_API_KEY: "proxy-zai-token"
|
|
28
|
+
};
|
|
29
|
+
new Set(Object.values(MODEL_PROXY_TOKENS));
|
|
30
|
+
new Set([
|
|
31
|
+
...Object.keys(MODEL_PROXY_TOKENS),
|
|
32
|
+
"TANGLE_API_KEY",
|
|
33
|
+
"GITHUB_TOKEN",
|
|
34
|
+
"GH_TOKEN"
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Fixed proxy slot names. The egress layer keys every secret it holds by an
|
|
38
|
+
* env-var-shaped name, and its persistence and recovery paths list those
|
|
39
|
+
* names; a declaration takes the slot at its index, so a sandbox with
|
|
40
|
+
* declarations needs no name the layer has not already listed.
|
|
41
|
+
*/
|
|
42
|
+
function declaredSecretSlotEnvVar(index) {
|
|
43
|
+
return `TANGLE_DECLARED_SLOT_${index}`;
|
|
44
|
+
}
|
|
45
|
+
/** The base placeholder for the slot at `index`; the box holds it salted. */
|
|
46
|
+
function declaredSecretBaseToken(index) {
|
|
47
|
+
return `proxy-declared-${index}-token`;
|
|
48
|
+
}
|
|
49
|
+
/** Every slot name mapped to its base placeholder. */
|
|
50
|
+
function declaredSecretSlotTokens() {
|
|
51
|
+
const slots = {};
|
|
52
|
+
for (let index = 0; index < 16; index++) slots[declaredSecretSlotEnvVar(index)] = declaredSecretBaseToken(index);
|
|
53
|
+
return slots;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region ../runtime-contracts/dist/runtime-environment.js
|
|
57
|
+
const SAFE_ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
58
|
+
function isSafeEnvVarName(name) {
|
|
59
|
+
if (typeof name !== "string") return false;
|
|
60
|
+
if (name.length === 0 || name.length > 256) return false;
|
|
61
|
+
return SAFE_ENV_VAR_NAME_RE.test(name);
|
|
62
|
+
}
|
|
63
|
+
const FORBIDDEN_ENV_VAR_NAMES = new Set([
|
|
64
|
+
"LD_PRELOAD",
|
|
65
|
+
"LD_LIBRARY_PATH",
|
|
66
|
+
"LD_AUDIT",
|
|
67
|
+
"DYLD_INSERT_LIBRARIES",
|
|
68
|
+
"DYLD_LIBRARY_PATH",
|
|
69
|
+
"DYLD_FALLBACK_LIBRARY_PATH",
|
|
70
|
+
"NODE_OPTIONS",
|
|
71
|
+
"NODE_PATH",
|
|
72
|
+
"NODE_TLS_REJECT_UNAUTHORIZED",
|
|
73
|
+
"PYTHONPATH",
|
|
74
|
+
"PYTHONSTARTUP",
|
|
75
|
+
"PERL5OPT",
|
|
76
|
+
"PERL5LIB",
|
|
77
|
+
"RUBYOPT",
|
|
78
|
+
"RUBYLIB",
|
|
79
|
+
"PATH",
|
|
80
|
+
"NIX_BIN_PATH",
|
|
81
|
+
"EGRESS_EDGE_POOL_ENABLED",
|
|
82
|
+
"EDGE_BIND_ID",
|
|
83
|
+
"PRIVACY_EGRESS",
|
|
84
|
+
"LOG_REDACT",
|
|
85
|
+
"IFS",
|
|
86
|
+
"BASH_ENV",
|
|
87
|
+
"ENV",
|
|
88
|
+
"SHELL",
|
|
89
|
+
"SHELLOPTS",
|
|
90
|
+
"PROMPT_COMMAND",
|
|
91
|
+
"HOME",
|
|
92
|
+
"XDG_CONFIG_HOME",
|
|
93
|
+
"XDG_DATA_HOME",
|
|
94
|
+
"XDG_CACHE_HOME",
|
|
95
|
+
"XDG_STATE_HOME",
|
|
96
|
+
"XDG_RUNTIME_DIR",
|
|
97
|
+
"HTTPS_PROXY",
|
|
98
|
+
"HTTP_PROXY",
|
|
99
|
+
"ALL_PROXY",
|
|
100
|
+
"NO_PROXY",
|
|
101
|
+
"https_proxy",
|
|
102
|
+
"http_proxy",
|
|
103
|
+
"all_proxy",
|
|
104
|
+
"no_proxy",
|
|
105
|
+
"SSL_CERT_FILE",
|
|
106
|
+
"SSL_CERT_DIR",
|
|
107
|
+
"REQUESTS_CA_BUNDLE",
|
|
108
|
+
"CURL_CA_BUNDLE",
|
|
109
|
+
"NODE_EXTRA_CA_CERTS",
|
|
110
|
+
"HOSTNAME",
|
|
111
|
+
"CONTAINER_ID",
|
|
112
|
+
"AGENT_WORKSPACE_ROOT",
|
|
113
|
+
"WORKSPACE_PATH",
|
|
114
|
+
"STORAGE_PATH",
|
|
115
|
+
"WORKSPACE_FILE_API_ROOT_ONLY",
|
|
116
|
+
"WORKSPACE_ALLOWED_ABSOLUTE_PATHS",
|
|
117
|
+
"TANGLE_PLAN_CALLBACK_ALLOWED_ORIGINS"
|
|
118
|
+
]);
|
|
119
|
+
const FORBIDDEN_ENV_VAR_PREFIXES = [
|
|
120
|
+
"SIDECAR_",
|
|
121
|
+
"ORCHESTRATOR_",
|
|
122
|
+
"AGENT_INTERNAL_",
|
|
123
|
+
"SANDBOX_DEV_",
|
|
124
|
+
"AGENT_SUBPROCESS_",
|
|
125
|
+
"TEE_ATTESTATION_"
|
|
126
|
+
];
|
|
127
|
+
const RUNTIME_CALLER_ALLOWED_ENV_NAMES = new Set(["SIDECAR_CAPABILITIES", "SIDECAR_PLATFORM_CONTROL_RUNTIME"]);
|
|
128
|
+
new Set(Object.values(HARNESS_WARM_TRANSPORT_ENV).flatMap(({ warmServer, prewarm }) => [warmServer, prewarm]));
|
|
129
|
+
function isForbiddenEnvVarName(name) {
|
|
130
|
+
if (RUNTIME_CALLER_ALLOWED_ENV_NAMES.has(name)) return false;
|
|
131
|
+
if (FORBIDDEN_ENV_VAR_NAMES.has(name)) return true;
|
|
132
|
+
for (const prefix of FORBIDDEN_ENV_VAR_PREFIXES) if (name.startsWith(prefix)) return true;
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Env record schema that enforces POSIX env-var name shape (via
|
|
137
|
+
* {@link isSafeEnvVarName}) on every key. Suitable for env that flows
|
|
138
|
+
* into a container the caller owns (user code), where names like
|
|
139
|
+
* `PATH`, `NODE_OPTIONS`, `LD_PRELOAD`, or `HTTPS_PROXY` are legitimate
|
|
140
|
+
* because the user controls the resulting process environment.
|
|
141
|
+
*
|
|
142
|
+
* Callers that merge env into the runtime's OWN process.env (sidecar
|
|
143
|
+
* `/config/env`, orchestrator `/sidecars/start`, project provisioning)
|
|
144
|
+
* MUST additionally reject the process-control blocklist via
|
|
145
|
+
* {@link isForbiddenEnvVarName} — see
|
|
146
|
+
* `apps/orchestrator/src/routes/sidecars.ts` and
|
|
147
|
+
* `apps/sidecar/src/routes/agents-config.ts` for the canonical shape.
|
|
148
|
+
*/
|
|
149
|
+
const safeEnvRecordSchema = z.record(z.string(), z.string()).refine((value) => Object.keys(value).every(isSafeEnvVarName), { message: "invalid env var name" });
|
|
150
|
+
/** Names only: the caller must keep a separate source and pass values to resume({ env }). */
|
|
151
|
+
const sandboxEnvRecoverySchema = z.object({ callerResupplies: z.array(z.string().max(256).refine(isSafeEnvVarName, { message: "invalid env var name" })).max(128).refine((keys) => new Set(keys).size === keys.length, { message: "callerResupplies must contain unique keys" }) }).strict();
|
|
152
|
+
z.object({
|
|
153
|
+
envRecovery: sandboxEnvRecoverySchema,
|
|
154
|
+
dryRun: z.boolean().optional()
|
|
155
|
+
}).strict();
|
|
156
|
+
z.object({
|
|
157
|
+
envRecovery: sandboxEnvRecoverySchema,
|
|
158
|
+
eligibleCallerResupplyKeys: z.array(z.string()),
|
|
159
|
+
requiredOnColdResumeKeys: z.array(z.string()),
|
|
160
|
+
automaticCredentialRecovery: z.literal(false),
|
|
161
|
+
dryRun: z.boolean()
|
|
162
|
+
}).strict();
|
|
163
|
+
safeEnvRecordSchema.refine((value) => Object.keys(value).every((key) => !isForbiddenEnvVarName(key) && !key.startsWith("SIDECAR_")), { message: "runtime-owned env var name cannot be set by callers" });
|
|
164
|
+
//#endregion
|
|
165
|
+
export { baseProxyToken as i, isSafeEnvVarName as n, declaredSecretSlotTokens as r, isForbiddenEnvVarName as t };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=harness-DIdVNSwl.mjs.map
|