@stigmer/runner 3.12.7 → 3.12.9
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/.build-fingerprint +1 -1
- package/dist/activities/execute-cursor/fetch-interceptor.js +29 -16
- package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +14 -0
- package/dist/activities/execute-cursor/index.js +76 -5
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +15 -9
- package/dist/activities/execute-cursor/message-translator.js +15 -9
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +9 -0
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/mcp-gate.d.ts +2 -0
- package/dist/activities/execute-deep-agent/mcp-gate.js +2 -1
- package/dist/activities/execute-deep-agent/mcp-gate.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +10 -1
- package/dist/activities/execute-deep-agent/setup.js +45 -3
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/payload-codecs.d.ts +1 -1
- package/dist/payload-codecs.js +6 -4
- package/dist/payload-codecs.js.map +1 -1
- package/dist/shared/memory-attachment.d.ts +97 -0
- package/dist/shared/memory-attachment.js +136 -0
- package/dist/shared/memory-attachment.js.map +1 -0
- package/dist/shared/memory-retrieval.d.ts +126 -0
- package/dist/shared/memory-retrieval.js +293 -0
- package/dist/shared/memory-retrieval.js.map +1 -0
- package/dist/shared/runner-credential-keys.js +2 -1
- package/dist/shared/runner-credential-keys.js.map +1 -1
- package/dist/shared/tool-kind.js +9 -0
- package/dist/shared/tool-kind.js.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/history-encryption-e2e.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -1
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +49 -15
- package/src/activities/execute-cursor/fetch-interceptor.ts +37 -16
- package/src/activities/execute-cursor/index.ts +86 -5
- package/src/activities/execute-cursor/message-translator.ts +15 -9
- package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +7 -0
- package/src/activities/execute-deep-agent/index.ts +10 -0
- package/src/activities/execute-deep-agent/mcp-gate.ts +4 -1
- package/src/activities/execute-deep-agent/setup.ts +70 -6
- package/src/payload-codecs.ts +12 -9
- package/src/shared/__tests__/memory-attachment.test.ts +167 -0
- package/src/shared/__tests__/memory-retrieval.test.ts +310 -0
- package/src/shared/memory-attachment.ts +167 -0
- package/src/shared/memory-retrieval.ts +383 -0
- package/src/shared/runner-credential-keys.ts +2 -1
- package/src/shared/tool-kind.ts +10 -0
- package/dist/claimcheck/compressor.d.ts +0 -2
- package/dist/claimcheck/compressor.js +0 -8
- package/dist/claimcheck/compressor.js.map +0 -1
- package/dist/claimcheck/config.d.ts +0 -7
- package/dist/claimcheck/config.js +0 -10
- package/dist/claimcheck/config.js.map +0 -1
- package/dist/claimcheck/index.d.ts +0 -3
- package/dist/claimcheck/index.js +0 -4
- package/dist/claimcheck/index.js.map +0 -1
- package/dist/claimcheck/payload-codec.d.ts +0 -23
- package/dist/claimcheck/payload-codec.js +0 -105
- package/dist/claimcheck/payload-codec.js.map +0 -1
- package/dist/encryption/config.d.ts +0 -64
- package/dist/encryption/config.js +0 -113
- package/dist/encryption/config.js.map +0 -1
- package/dist/encryption/index.d.ts +0 -3
- package/dist/encryption/index.js +0 -3
- package/dist/encryption/index.js.map +0 -1
- package/dist/encryption/payload-codec.d.ts +0 -41
- package/dist/encryption/payload-codec.js +0 -130
- package/dist/encryption/payload-codec.js.map +0 -1
- package/src/__tests__/claimcheck-codec.test.ts +0 -256
- package/src/__tests__/encryption-codec.test.ts +0 -287
- package/src/__tests__/fixtures/encrypted-payload-fixture.json +0 -15
- package/src/claimcheck/compressor.ts +0 -9
- package/src/claimcheck/config.ts +0 -20
- package/src/claimcheck/index.ts +0 -3
- package/src/claimcheck/payload-codec.ts +0 -139
- package/src/encryption/config.ts +0 -161
- package/src/encryption/index.ts +0 -3
- package/src/encryption/payload-codec.ts +0 -152
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Temporal PayloadCodec that encrypts payloads at rest in workflow
|
|
3
|
-
* history (stigmer-cloud#227).
|
|
4
|
-
*
|
|
5
|
-
* Why: the workflow engine runs inside the Temporal deterministic
|
|
6
|
-
* sandbox, so decrypted execution-context values cross the history
|
|
7
|
-
* boundary in many places — the hydrate activity result, the runtime
|
|
8
|
-
* env passed as an input to every per-task activity, and expression
|
|
9
|
-
* results recorded as local-activity markers. Encrypting at the payload
|
|
10
|
-
* codec layer closes the entire class with one mechanism instead of
|
|
11
|
-
* chasing each crossing.
|
|
12
|
-
*
|
|
13
|
-
* Envelope (cross-SDK contract — the Java decode-only codec in
|
|
14
|
-
* stigmer-cloud's temporal-starter must match it byte-for-byte, pinned
|
|
15
|
-
* by the conformance fixture in __tests__/fixtures/):
|
|
16
|
-
*
|
|
17
|
-
* metadata: encoding = "binary/encrypted"
|
|
18
|
-
* encryption-key-id = <key id that encrypted this payload>
|
|
19
|
-
* data: iv (12 bytes) ‖ AES-256-GCM(ciphertext ‖ tag (16 bytes))
|
|
20
|
-
*
|
|
21
|
-
* The plaintext is the serialized ORIGINAL Payload proto (metadata AND
|
|
22
|
-
* data), so decode restores the payload exactly — including its
|
|
23
|
-
* original encoding — with no side channel.
|
|
24
|
-
*
|
|
25
|
-
* Decode passes through payloads it did not encode. This is what keeps
|
|
26
|
-
* plaintext signals from the Java/Go orchestrators and pre-rollout
|
|
27
|
-
* in-flight histories working with zero migration. Everything else
|
|
28
|
-
* fails closed: unknown key id, missing key id, and ciphertext tampering
|
|
29
|
-
* all throw rather than surfacing bogus payloads.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
33
|
-
import type { Payload, PayloadCodec } from "@temporalio/common";
|
|
34
|
-
// Default-import + destructure, NOT `import { temporal } from …`:
|
|
35
|
-
// @temporalio/proto is CommonJS and its `temporal` export defeats Node's
|
|
36
|
-
// cjs-module-lexer named-export detection, so the named form loads under
|
|
37
|
-
// tsx/vitest (their interop is looser) but crashes plain `node dist/main.js`
|
|
38
|
-
// at startup with "Named export 'temporal' not found" (stigmer/stigmer#399
|
|
39
|
-
// boot regression). Pinned by scripts/verify-dist-boot.mjs in CI.
|
|
40
|
-
import proto from "@temporalio/proto";
|
|
41
|
-
import type { EncryptionKey, PayloadEncryptionConfig } from "./config.js";
|
|
42
|
-
|
|
43
|
-
const { temporal } = proto;
|
|
44
|
-
|
|
45
|
-
const ENCODING_METADATA_KEY = "encoding";
|
|
46
|
-
const ENCRYPTED_ENCODING_VALUE = "binary/encrypted";
|
|
47
|
-
const KEY_ID_METADATA_KEY = "encryption-key-id";
|
|
48
|
-
|
|
49
|
-
/** AES-GCM parameters shared with the Java implementation. */
|
|
50
|
-
const IV_BYTES = 12;
|
|
51
|
-
const AUTH_TAG_BYTES = 16;
|
|
52
|
-
|
|
53
|
-
export class EncryptionPayloadCodec implements PayloadCodec {
|
|
54
|
-
private readonly decryptKeysById: Map<string, Buffer>;
|
|
55
|
-
|
|
56
|
-
constructor(private readonly config: PayloadEncryptionConfig) {
|
|
57
|
-
this.decryptKeysById = new Map([[config.primary.keyId, config.primary.key]]);
|
|
58
|
-
if (config.secondary) {
|
|
59
|
-
this.decryptKeysById.set(config.secondary.keyId, config.secondary.key);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async encode(payloads: Payload[]): Promise<Payload[]> {
|
|
64
|
-
return payloads.map((p) => this.encodePayload(p));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async decode(payloads: Payload[]): Promise<Payload[]> {
|
|
68
|
-
return payloads.map((p) => this.decodePayload(p));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private encodePayload(payload: Payload): Payload {
|
|
72
|
-
// Data-less payloads (binary/null from void results) stay as-is:
|
|
73
|
-
// there is nothing to protect, and the cross-language parents that
|
|
74
|
-
// await our workflows as void must be able to read them without a key.
|
|
75
|
-
if (!payload.data || payload.data.length === 0) {
|
|
76
|
-
return payload;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const plaintext = temporal.api.common.v1.Payload.encode(payload).finish();
|
|
80
|
-
return {
|
|
81
|
-
metadata: {
|
|
82
|
-
[ENCODING_METADATA_KEY]: Buffer.from(ENCRYPTED_ENCODING_VALUE),
|
|
83
|
-
[KEY_ID_METADATA_KEY]: Buffer.from(this.config.primary.keyId),
|
|
84
|
-
},
|
|
85
|
-
data: encrypt(plaintext, this.config.primary),
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private decodePayload(payload: Payload): Payload {
|
|
90
|
-
if (!isEncryptedPayload(payload)) {
|
|
91
|
-
return payload;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const keyIdBytes = payload.metadata?.[KEY_ID_METADATA_KEY];
|
|
95
|
-
if (!keyIdBytes) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"Encrypted payload is missing its encryption-key-id metadata — refusing to decode",
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
const keyId = Buffer.from(keyIdBytes).toString("utf-8");
|
|
101
|
-
const key = this.decryptKeysById.get(keyId);
|
|
102
|
-
if (!key) {
|
|
103
|
-
throw new Error(
|
|
104
|
-
`Encrypted payload uses unknown key id '${keyId}' — configure it as the ` +
|
|
105
|
-
`primary or secondary payload encryption key (rotation window?)`,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const plaintext = decrypt(payload.data!, key, keyId);
|
|
110
|
-
return temporal.api.common.v1.Payload.decode(plaintext);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function isEncryptedPayload(payload: Payload): boolean {
|
|
115
|
-
const encoding = payload.metadata?.[ENCODING_METADATA_KEY];
|
|
116
|
-
if (!encoding) return false;
|
|
117
|
-
return Buffer.from(encoding).toString("utf-8") === ENCRYPTED_ENCODING_VALUE;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function encrypt(plaintext: Uint8Array, key: EncryptionKey): Buffer {
|
|
121
|
-
const iv = randomBytes(IV_BYTES);
|
|
122
|
-
const cipher = createCipheriv("aes-256-gcm", key.key, iv);
|
|
123
|
-
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
124
|
-
// Layout iv ‖ ciphertext ‖ tag matches Java's AES/GCM/NoPadding, whose
|
|
125
|
-
// doFinal() output is ciphertext ‖ tag.
|
|
126
|
-
return Buffer.concat([iv, ciphertext, cipher.getAuthTag()]);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function decrypt(data: Uint8Array, key: Buffer, keyId: string): Buffer {
|
|
130
|
-
if (data.length < IV_BYTES + AUTH_TAG_BYTES) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
`Encrypted payload under key id '${keyId}' is truncated (${data.length} bytes)`,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
const buf = Buffer.from(data);
|
|
136
|
-
const iv = buf.subarray(0, IV_BYTES);
|
|
137
|
-
const ciphertext = buf.subarray(IV_BYTES, buf.length - AUTH_TAG_BYTES);
|
|
138
|
-
const tag = buf.subarray(buf.length - AUTH_TAG_BYTES);
|
|
139
|
-
|
|
140
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
141
|
-
decipher.setAuthTag(tag);
|
|
142
|
-
try {
|
|
143
|
-
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
144
|
-
} catch {
|
|
145
|
-
// GCM auth failure: tampered ciphertext or a key that does not match
|
|
146
|
-
// its advertised id. Never surface partially decrypted bytes.
|
|
147
|
-
throw new Error(
|
|
148
|
-
`Failed to decrypt payload under key id '${keyId}' — ciphertext is ` +
|
|
149
|
-
`corrupt or the configured key does not match`,
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
}
|