@tangle-network/agent-profile-materialize 0.26.4 → 0.26.6
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.
|
@@ -20,5 +20,5 @@ export declare function assertPrivateManagedRoot(root: string): void;
|
|
|
20
20
|
* The caller must keep the returned tree while an admitted turn uses it and
|
|
21
21
|
* dispose it after that turn, so a later binding cannot expose old secrets.
|
|
22
22
|
*/
|
|
23
|
-
export declare function prepareManagedWorkspacePlan(plan: WorkspacePlan, managedRoot: string, sharedWorkspaceDir: string, secretProvider: AgentProfileSecretProvider, options?: Pick<ApplyWorkspacePlanOptions, "ownership" | "runtimeOnlyFiles" | "
|
|
23
|
+
export declare function prepareManagedWorkspacePlan(plan: WorkspacePlan, managedRoot: string, sharedWorkspaceDir: string, secretProvider: AgentProfileSecretProvider, options?: Pick<ApplyWorkspacePlanOptions, "ownership" | "runtimeOnlyFiles" | "secretFileSlotReferences">): Promise<PreparedManagedWorkspace>;
|
|
24
24
|
export declare function lstatIfPresent(path: string): ReturnType<typeof lstatSync> | null;
|
package/dist/plan-application.js
CHANGED
|
@@ -9,7 +9,7 @@ export function applyWorkspacePlan(plan, workspaceDir, options = {}) {
|
|
|
9
9
|
*/
|
|
10
10
|
export async function applyWorkspacePlanWithSecretProvider(plan, workspaceDir, secretProvider, options = {}) {
|
|
11
11
|
const planDigest = hashWorkspacePlan(plan);
|
|
12
|
-
const resolved = await resolvePrivateWorkspacePlan(plan, secretProvider, options.
|
|
12
|
+
const resolved = await resolvePrivateWorkspacePlan(plan, secretProvider, options.secretFileSlotReferences);
|
|
13
13
|
return applyResolvedWorkspacePlan(plan, resolved, workspaceDir, options, planDigest);
|
|
14
14
|
}
|
|
15
15
|
function secretRefLabel(ref) {
|
|
@@ -93,7 +93,7 @@ function secretSlotEnvironmentName(ref) {
|
|
|
93
93
|
.toUpperCase();
|
|
94
94
|
return `TANGLE_PROFILE_SECRET_${digest}`;
|
|
95
95
|
}
|
|
96
|
-
async function resolvePrivateWorkspacePlan(plan, secretProvider,
|
|
96
|
+
async function resolvePrivateWorkspacePlan(plan, secretProvider, fileSlotReferences) {
|
|
97
97
|
if (!secretProvider || typeof secretProvider.get !== "function") {
|
|
98
98
|
throw new Error("AgentProfileSecretProvider.get is required");
|
|
99
99
|
}
|
|
@@ -106,8 +106,10 @@ async function resolvePrivateWorkspacePlan(plan, secretProvider, fileSlotsByRefe
|
|
|
106
106
|
try {
|
|
107
107
|
value = await secretProvider.get(ref.key);
|
|
108
108
|
}
|
|
109
|
-
catch {
|
|
110
|
-
|
|
109
|
+
catch (cause) {
|
|
110
|
+
// The executor's refusal (a key it will not serve) rides along as
|
|
111
|
+
// the cause; a provider error carries no resolved value.
|
|
112
|
+
throw new Error(`AgentProfile secret provider failed for ${secretRefLabel(ref)}`, { cause });
|
|
111
113
|
}
|
|
112
114
|
return requireResolvedSecretValue(ref, value);
|
|
113
115
|
})();
|
|
@@ -123,7 +125,7 @@ async function resolvePrivateWorkspacePlan(plan, secretProvider, fileSlotsByRefe
|
|
|
123
125
|
const resolveFileSlot = async (input) => {
|
|
124
126
|
const ref = agentProfileSecretRefSchema.parse(input);
|
|
125
127
|
const value = await resolveRawRef(ref);
|
|
126
|
-
if (!
|
|
128
|
+
if (!fileSlotReferences) {
|
|
127
129
|
return ref.format === "bearer" ? `Bearer ${value}` : value;
|
|
128
130
|
}
|
|
129
131
|
// Never write the value in place: the file is readable by the process
|
|
@@ -133,6 +135,7 @@ async function resolvePrivateWorkspacePlan(plan, secretProvider, fileSlotsByRefe
|
|
|
133
135
|
throw new Error(`AgentProfile secret ${secretRefLabel(ref)} has a value that cannot be referenced from a secret OpenCode config: it may hold only printable ASCII without quotes, backslashes or braces`);
|
|
134
136
|
}
|
|
135
137
|
const name = secretSlotEnvironmentName(ref);
|
|
138
|
+
fileSlotReferences[name] = value;
|
|
136
139
|
return ref.format === "bearer" ? `Bearer {env:${name}}` : `{env:${name}}`;
|
|
137
140
|
};
|
|
138
141
|
const files = await Promise.all(normalizePlanFiles(plan.files).map(async (file) => {
|
package/dist/plan-types.d.ts
CHANGED
|
@@ -323,11 +323,13 @@ export interface ApplyWorkspacePlanOptions {
|
|
|
323
323
|
/**
|
|
324
324
|
* Write every JSON file secret slot as an `{env:NAME}` reference (OpenCode
|
|
325
325
|
* config substitution) and never its value, so file bytes and every digest
|
|
326
|
-
* over them stay identical when only a secret's value changes. The value
|
|
327
|
-
*
|
|
328
|
-
*
|
|
326
|
+
* over them stay identical when only a secret's value changes. The value
|
|
327
|
+
* lands here under NAME for the executor alone: never put it in the launch
|
|
328
|
+
* environment, argv or any file the native process reads, because that
|
|
329
|
+
* process hands everything it holds to every tool it runs. A value that
|
|
330
|
+
* could not be substituted safely is refused.
|
|
329
331
|
*/
|
|
330
|
-
|
|
332
|
+
secretFileSlotReferences?: Record<string, string>;
|
|
331
333
|
}
|
|
332
334
|
import type { AgentProfileSecretRef } from "@tangle-network/agent-interface";
|
|
333
335
|
import type { HarnessId } from "./harness.js";
|
|
@@ -18,5 +18,13 @@ export declare function prepareSecretConcurrentProfileRevision(input: {
|
|
|
18
18
|
namingKey: Uint8Array;
|
|
19
19
|
secretProvider: AgentProfileSecretProvider;
|
|
20
20
|
options?: Pick<ApplyWorkspacePlanOptions, "runtimeOnlyFiles">;
|
|
21
|
-
}): Promise<ConcurrentProfileRevision
|
|
21
|
+
}): Promise<ConcurrentProfileRevision & {
|
|
22
|
+
/**
|
|
23
|
+
* The value behind each `{env:NAME}` reference in the revision's config,
|
|
24
|
+
* for the executor alone: the launch never receives them. An executor
|
|
25
|
+
* that serves a referencing MCP server through its own loopback proxy
|
|
26
|
+
* resolves the server's headers here.
|
|
27
|
+
*/
|
|
28
|
+
secretReferences: Readonly<Record<string, string>>;
|
|
29
|
+
}>;
|
|
22
30
|
export declare function runSetfacl(args: string[], paths: readonly string[]): void;
|
|
@@ -66,7 +66,8 @@ export async function prepareSecretConcurrentProfileRevision(input) {
|
|
|
66
66
|
assertLaunchRoot(input.launchRoot);
|
|
67
67
|
// File slots reference their secrets, so an unchanged profile with a rotated
|
|
68
68
|
// per-turn secret reuses this revision.
|
|
69
|
-
const
|
|
69
|
+
const secretReferences = {};
|
|
70
|
+
const prepared = await prepareManagedWorkspacePlan(plan, input.managedRoot, input.sharedWorkspaceDir, input.secretProvider, { ...input.options, secretFileSlotReferences: secretReferences });
|
|
70
71
|
try {
|
|
71
72
|
// XDG_CONFIG_HOME is bound to this executor-owned tree at native launch.
|
|
72
73
|
// An agent-owned HOME may hold SQLite state, never native authority.
|
|
@@ -125,6 +126,7 @@ export async function prepareSecretConcurrentProfileRevision(input) {
|
|
|
125
126
|
directory,
|
|
126
127
|
manifest: prepared.manifest,
|
|
127
128
|
application: { ...prepared.application, spawn },
|
|
129
|
+
secretReferences,
|
|
128
130
|
};
|
|
129
131
|
}
|
|
130
132
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-profile-materialize",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.6",
|
|
4
4
|
"description": "Materialize an AgentProfile into the native per-harness workspace files (the one shared materializer for cli-bridge, agent-container, and VB).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@tangle-network/agent-interface": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
|
36
36
|
},
|
|
37
37
|
"tangleRelease": {
|
|
38
|
-
"sourceSha": "
|
|
39
|
-
"mergedAt": "2026-10-
|
|
38
|
+
"sourceSha": "9b8b29a6dca8c8affb5f0ed0266be7ea008a2c3d",
|
|
39
|
+
"mergedAt": "2026-10-19T07:15:28-06:00"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -p tsconfig.json",
|