@forgezero/agent 0.1.39 → 0.1.40
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/README.md +91 -18
- package/dist/agent-heartbeat.js +16 -14
- package/dist/agent-update-helper.js +15 -13
- package/dist/agent-update.js +15 -13
- package/dist/bootstrap.d.ts +13 -0
- package/dist/bootstrap.js +244 -832
- package/dist/cli/index.d.ts +0 -2
- package/dist/cloudflare-bootstrap.d.ts +21 -128
- package/dist/cloudflare-bootstrap.js +146 -788
- package/dist/cloudflare-edge.d.ts +3 -151
- package/dist/cloudflare-edge.js +28 -248
- package/dist/credential-schema.d.ts +60 -0
- package/dist/credential-schema.js +335 -0
- package/dist/definition.js +2 -2
- package/dist/deploy-file.js +2 -2
- package/dist/fz-agent.js +199 -47
- package/dist/fz.js +536 -1544
- package/dist/index.d.ts +33 -0
- package/dist/metal-bootstrap.js +1 -1
- package/dist/platform-bootstrap-runtime.d.ts +5 -0
- package/dist/platform-bootstrap-runtime.js +25 -6
- package/dist/project-context.js +1 -1
- package/dist/provision.js +18 -16
- package/dist/software-helper.js +2 -2
- package/dist/software.js +2 -2
- package/dist/version.d.ts +1 -1
- package/package.json +8 -4
- package/dist/cli/custody.d.ts +0 -35
package/dist/fz-agent.js
CHANGED
|
@@ -5814,31 +5814,86 @@ function deriveKeysFromSeed(seed) {
|
|
|
5814
5814
|
const edPublic = ed25519.getPublicKey(edSecret);
|
|
5815
5815
|
const mlKeys = ml_dsa65.keygen(mlSeed);
|
|
5816
5816
|
mlSeed.fill(0);
|
|
5817
|
-
|
|
5817
|
+
const result = {
|
|
5818
5818
|
ed25519: { publicKey: b64(edPublic), secretKey: b64(edSecret) },
|
|
5819
5819
|
mlDsa: { publicKey: b64(mlKeys.publicKey), secretKey: b64(mlKeys.secretKey) }
|
|
5820
5820
|
};
|
|
5821
|
+
edSecret.fill(0);
|
|
5822
|
+
mlKeys.secretKey.fill(0);
|
|
5823
|
+
return result;
|
|
5821
5824
|
}
|
|
5822
5825
|
var RESPONSE_KEY_HEADER = "x-fz-response-key";
|
|
5826
|
+
var REQUEST_SIGNATURE_SUITE = "ed25519+ml-dsa-65";
|
|
5827
|
+
var RESPONSE_SEALING_SUITE = "ml-kem-768+x25519/aes-256-gcm";
|
|
5828
|
+
var BASE64URL = /^[A-Za-z0-9_-]+$/;
|
|
5829
|
+
var encodedLength = (bytes) => Math.ceil(bytes * 4 / 3);
|
|
5830
|
+
var length = (value, name) => {
|
|
5831
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
5832
|
+
throw new Error(`identity: ${name} length unavailable`);
|
|
5833
|
+
return value;
|
|
5834
|
+
};
|
|
5835
|
+
var ED_PUBLIC_BYTES = length(ed25519.lengths.publicKey, "Ed25519 public key");
|
|
5836
|
+
var ED_SIGNATURE_BYTES = length(ed25519.lengths.signature, "Ed25519 signature");
|
|
5837
|
+
var ML_PUBLIC_BYTES = length(ml_dsa65.lengths.publicKey, "ML-DSA-65 public key");
|
|
5838
|
+
var ML_SIGNATURE_BYTES = length(ml_dsa65.lengths.signature, "ML-DSA-65 signature");
|
|
5839
|
+
var RESPONSE_PUBLIC_BYTES = length(ml_kem768_x25519.lengths.publicKey, "hybrid response public key");
|
|
5840
|
+
var RESPONSE_SECRET_BYTES = length(ml_kem768_x25519.lengths.secretKey, "hybrid response secret key");
|
|
5841
|
+
var RESPONSE_CIPHERTEXT_BYTES = length(ml_kem768_x25519.lengths.cipherText, "hybrid response ciphertext");
|
|
5842
|
+
function exactBytes(value, bytes) {
|
|
5843
|
+
if (typeof value !== "string" || value.length !== encodedLength(bytes) || !BASE64URL.test(value))
|
|
5844
|
+
return null;
|
|
5845
|
+
try {
|
|
5846
|
+
const decoded = un64(value);
|
|
5847
|
+
return decoded.length === bytes && b64(decoded) === value ? decoded : null;
|
|
5848
|
+
} catch {
|
|
5849
|
+
return null;
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
function validIdentity(value) {
|
|
5853
|
+
return typeof value === "string" && value.length >= 1 && value.length <= 128 && !/[^A-Za-z0-9_.:@/-]/.test(value) && !/[\0\r\n]/.test(value);
|
|
5854
|
+
}
|
|
5855
|
+
function validResponsePublicKey(value) {
|
|
5856
|
+
return exactBytes(value, RESPONSE_PUBLIC_BYTES) !== null;
|
|
5857
|
+
}
|
|
5823
5858
|
function generateResponseRecipient() {
|
|
5824
5859
|
const pair = ml_kem768_x25519.keygen();
|
|
5825
5860
|
return { publicKey: b64(pair.publicKey), secretKey: b64(pair.secretKey) };
|
|
5826
5861
|
}
|
|
5827
5862
|
var responseKey = (sharedSecret) => hkdf(sha256, sharedSecret, undefined, ENCODER.encode("forgezero/response/ml-kem-768+x25519/v1"), 32);
|
|
5828
5863
|
async function openResponse(recipientSecretKey, requestBinding, envelope) {
|
|
5829
|
-
if (
|
|
5864
|
+
if (!requestBinding || requestBinding.length > 16384 || /[\0\r\n]/.test(requestBinding)) {
|
|
5865
|
+
throw new Error("response: malformed request binding");
|
|
5866
|
+
}
|
|
5867
|
+
if (envelope?.version !== 1 || envelope.suite !== RESPONSE_SEALING_SUITE) {
|
|
5830
5868
|
throw new Error("response: unsupported sealed response");
|
|
5831
|
-
|
|
5869
|
+
}
|
|
5870
|
+
const kemCiphertext = exactBytes(envelope.kemCiphertext, RESPONSE_CIPHERTEXT_BYTES);
|
|
5871
|
+
const nonce = exactBytes(envelope.nonce, 12);
|
|
5872
|
+
if (!kemCiphertext || !nonce || typeof envelope.ciphertext !== "string" || envelope.ciphertext.length < encodedLength(16) || envelope.ciphertext.length > encodedLength(16 * 1024 * 1024) || !BASE64URL.test(envelope.ciphertext)) {
|
|
5873
|
+
throw new Error("response: malformed sealed response");
|
|
5874
|
+
}
|
|
5875
|
+
let encodedCiphertext;
|
|
5876
|
+
try {
|
|
5877
|
+
encodedCiphertext = un64(envelope.ciphertext);
|
|
5878
|
+
} catch {
|
|
5879
|
+
throw new Error("response: malformed sealed response");
|
|
5880
|
+
}
|
|
5881
|
+
if (encodedCiphertext.length < 16 || encodedCiphertext.length > 16 * 1024 * 1024 || b64(encodedCiphertext) !== envelope.ciphertext) {
|
|
5882
|
+
throw new Error("response: malformed sealed response");
|
|
5883
|
+
}
|
|
5884
|
+
const sharedSecret = ml_kem768_x25519.decapsulate(kemCiphertext, exactBytes(recipientSecretKey, RESPONSE_SECRET_BYTES) ?? (() => {
|
|
5885
|
+
throw new Error("response: malformed recipient secret key");
|
|
5886
|
+
})());
|
|
5832
5887
|
const rawKey = responseKey(sharedSecret);
|
|
5833
5888
|
sharedSecret.fill(0);
|
|
5834
5889
|
const key = await crypto.subtle.importKey("raw", new Uint8Array(rawKey), "AES-GCM", false, ["decrypt"]);
|
|
5835
5890
|
rawKey.fill(0);
|
|
5836
5891
|
const decrypted = new Uint8Array(await crypto.subtle.decrypt({
|
|
5837
5892
|
name: "AES-GCM",
|
|
5838
|
-
iv: new Uint8Array(
|
|
5893
|
+
iv: new Uint8Array(nonce),
|
|
5839
5894
|
additionalData: new Uint8Array(ENCODER.encode(requestBinding)),
|
|
5840
5895
|
tagLength: 128
|
|
5841
|
-
}, key, new Uint8Array(
|
|
5896
|
+
}, key, new Uint8Array(encodedCiphertext)));
|
|
5842
5897
|
try {
|
|
5843
5898
|
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
5844
5899
|
} finally {
|
|
@@ -5846,6 +5901,8 @@ async function openResponse(recipientSecretKey, requestBinding, envelope) {
|
|
|
5846
5901
|
}
|
|
5847
5902
|
}
|
|
5848
5903
|
var SIGNATURE_FIELDS = (envelope) => ({
|
|
5904
|
+
version: envelope.version,
|
|
5905
|
+
suite: envelope.suite,
|
|
5849
5906
|
timestamp: envelope.timestamp,
|
|
5850
5907
|
nonce: envelope.nonce,
|
|
5851
5908
|
edSignature: envelope.edSignature,
|
|
@@ -5855,9 +5912,15 @@ function encodeSignatureHeader(envelope) {
|
|
|
5855
5912
|
return b64(ENCODER.encode(JSON.stringify(SIGNATURE_FIELDS(envelope))));
|
|
5856
5913
|
}
|
|
5857
5914
|
function canonicalString(args) {
|
|
5915
|
+
if (!validIdentity(args.identity) || !/^[A-Za-z][A-Za-z0-9-]{0,31}$/.test(args.method) || /[\0\r\n]/.test(args.path) || /[\0\r\n]/.test(args.query) || !exactBytes(args.nonce, 16) || args.responseKey !== undefined && !validResponsePublicKey(args.responseKey)) {
|
|
5916
|
+
throw new Error("identity: malformed canonical request");
|
|
5917
|
+
}
|
|
5858
5918
|
const body = typeof args.body === "string" ? ENCODER.encode(args.body) : args.body;
|
|
5859
5919
|
const digest = Array.from(sha256(body), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
5860
5920
|
const fields = [
|
|
5921
|
+
"forgezero/request-signature/v1",
|
|
5922
|
+
REQUEST_SIGNATURE_SUITE,
|
|
5923
|
+
args.identity,
|
|
5861
5924
|
args.method.toUpperCase(),
|
|
5862
5925
|
args.path,
|
|
5863
5926
|
args.query ?? "",
|
|
@@ -5865,16 +5928,17 @@ function canonicalString(args) {
|
|
|
5865
5928
|
args.nonce,
|
|
5866
5929
|
digest
|
|
5867
5930
|
];
|
|
5868
|
-
|
|
5869
|
-
fields.push(args.responseKey);
|
|
5931
|
+
fields.push(args.responseKey ?? "-");
|
|
5870
5932
|
return fields.join(`
|
|
5871
5933
|
`);
|
|
5872
5934
|
}
|
|
5873
5935
|
function signRequest(keys, nodeKey, args) {
|
|
5874
5936
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
5875
5937
|
const nonce = b64(randomBytes6(16));
|
|
5876
|
-
const message = ENCODER.encode(canonicalString({ ...args, query: args.query ?? "", timestamp, nonce }));
|
|
5938
|
+
const message = ENCODER.encode(canonicalString({ ...args, identity: nodeKey, query: args.query ?? "", timestamp, nonce }));
|
|
5877
5939
|
return {
|
|
5940
|
+
version: 1,
|
|
5941
|
+
suite: REQUEST_SIGNATURE_SUITE,
|
|
5878
5942
|
nodeKey,
|
|
5879
5943
|
timestamp,
|
|
5880
5944
|
nonce,
|
|
@@ -6664,8 +6728,8 @@ var UBUNTU_2604_X64 = [
|
|
|
6664
6728
|
},
|
|
6665
6729
|
{
|
|
6666
6730
|
requirement: { id: "arangodb", version: "3.11.14" },
|
|
6667
|
-
check: `arangod --version 2>/dev/null | head -1 | grep -q '3.11.14'`,
|
|
6668
|
-
install: `tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT; ` + `curl -fsSL 'https://download.arangodb.com/arangodb311/DEBIAN/amd64/arangodb3_3.11.14-1_amd64.deb' -o "$tmp/arangodb.deb"; ` + `echo "${ARANGO_SHA256} $tmp/arangodb.deb" | sha256sum -c -; ` + `DEBIAN_FRONTEND=noninteractive dpkg -i "$tmp/arangodb.deb" >/dev/null 2>&1 || ` + `DEBIAN_FRONTEND=noninteractive apt-get -y -f install`
|
|
6731
|
+
check: `arangod --version 2>/dev/null | head -1 | grep -q '3.11.14' && ` + `! systemctl is-active --quiet arangodb3.service && ` + `! systemctl is-enabled --quiet arangodb3.service`,
|
|
6732
|
+
install: `tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT; ` + `curl -fsSL 'https://download.arangodb.com/arangodb311/DEBIAN/amd64/arangodb3_3.11.14-1_amd64.deb' -o "$tmp/arangodb.deb"; ` + `echo "${ARANGO_SHA256} $tmp/arangodb.deb" | sha256sum -c -; ` + `DEBIAN_FRONTEND=noninteractive dpkg -i "$tmp/arangodb.deb" >/dev/null 2>&1 || ` + `DEBIAN_FRONTEND=noninteractive apt-get -y -f install; ` + `systemctl disable --now arangodb3.service`
|
|
6669
6733
|
},
|
|
6670
6734
|
{
|
|
6671
6735
|
requirement: { id: "cloudflared", version: "2026.7.3" },
|
|
@@ -10271,6 +10335,8 @@ var checked4 = async (run, input, label) => {
|
|
|
10271
10335
|
return result;
|
|
10272
10336
|
};
|
|
10273
10337
|
async function validateReleaseDirectory(directory, release, run) {
|
|
10338
|
+
chmodSync10(directory, 493);
|
|
10339
|
+
chmodSync10(join5(directory, "dist"), 493);
|
|
10274
10340
|
const manifest = JSON.parse(readFileSync7(join5(directory, "package.json"), "utf8"));
|
|
10275
10341
|
if (manifest.name !== release.package || manifest.version !== release.version) {
|
|
10276
10342
|
throw new Error("agent update manifest does not match the selected release");
|
|
@@ -10321,19 +10387,19 @@ async function stageAgentRelease(releaseInput, options) {
|
|
|
10321
10387
|
if (!timingSafeEqual(actual, expected))
|
|
10322
10388
|
throw new Error("agent update integrity mismatch");
|
|
10323
10389
|
writeFileSync7(archive, bytes, { mode: 384, flag: "wx" });
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
"
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
}
|
|
10390
|
+
for (const [member, relative] of [
|
|
10391
|
+
["package/package.json", "package.json"],
|
|
10392
|
+
["package/dist/fz-agent.js", "dist/fz-agent.js"],
|
|
10393
|
+
["package/dist/fz.js", "dist/fz.js"]
|
|
10394
|
+
]) {
|
|
10395
|
+
const extracted = await checked4(run, {
|
|
10396
|
+
command: "/usr/bin/tar",
|
|
10397
|
+
args: ["-xOzf", archive, member]
|
|
10398
|
+
}, `agent update extraction of ${member}`);
|
|
10399
|
+
const destination = join5(unpacked, relative);
|
|
10400
|
+
mkdirSync6(dirname4(destination), { recursive: true, mode: 448 });
|
|
10401
|
+
writeFileSync7(destination, extracted.output, { mode: 384, flag: "wx" });
|
|
10402
|
+
}
|
|
10337
10403
|
await validateReleaseDirectory(unpacked, release, run);
|
|
10338
10404
|
if (!existsSync10(finalDirectory)) {
|
|
10339
10405
|
renameSync4(unpacked, finalDirectory);
|
|
@@ -10852,7 +10918,7 @@ function requestAgentUpdate(request, socketPath = DEFAULT_AGENT_UPDATE_SOCKET, t
|
|
|
10852
10918
|
import { readFileSync as readFileSync9 } from "fs";
|
|
10853
10919
|
|
|
10854
10920
|
// src/version.ts
|
|
10855
|
-
var VERSION3 = "0.1.
|
|
10921
|
+
var VERSION3 = "0.1.40";
|
|
10856
10922
|
|
|
10857
10923
|
// src/agent-heartbeat.ts
|
|
10858
10924
|
var unquote = (value) => value.replace(/^['"]|['"]$/g, "");
|
|
@@ -11506,21 +11572,21 @@ async function boundedResponseJson(response) {
|
|
|
11506
11572
|
return null;
|
|
11507
11573
|
const reader = response.body.getReader();
|
|
11508
11574
|
const chunks = [];
|
|
11509
|
-
let
|
|
11575
|
+
let length2 = 0;
|
|
11510
11576
|
while (true) {
|
|
11511
11577
|
const next = await reader.read();
|
|
11512
11578
|
if (next.done)
|
|
11513
11579
|
break;
|
|
11514
|
-
|
|
11515
|
-
if (
|
|
11580
|
+
length2 += next.value.byteLength;
|
|
11581
|
+
if (length2 > AGENT_OTLP_MAX_RESPONSE_BYTES) {
|
|
11516
11582
|
await reader.cancel();
|
|
11517
11583
|
throw new PermanentExportError;
|
|
11518
11584
|
}
|
|
11519
11585
|
chunks.push(next.value);
|
|
11520
11586
|
}
|
|
11521
|
-
if (
|
|
11587
|
+
if (length2 === 0)
|
|
11522
11588
|
return null;
|
|
11523
|
-
const bytes = new Uint8Array(
|
|
11589
|
+
const bytes = new Uint8Array(length2);
|
|
11524
11590
|
let offset = 0;
|
|
11525
11591
|
for (const chunk of chunks) {
|
|
11526
11592
|
bytes.set(chunk, offset);
|
|
@@ -11961,6 +12027,56 @@ class AgentTelemetryRuntime {
|
|
|
11961
12027
|
}
|
|
11962
12028
|
}
|
|
11963
12029
|
|
|
12030
|
+
// src/credential-schema.ts
|
|
12031
|
+
var AGENT_CREDENTIAL_LOCATIONS = [
|
|
12032
|
+
"operator",
|
|
12033
|
+
"metal",
|
|
12034
|
+
"platform-compute",
|
|
12035
|
+
"tenant-compute"
|
|
12036
|
+
];
|
|
12037
|
+
var AGENT_CREDENTIAL_POLICY = {
|
|
12038
|
+
operator: { vault: false, systemdFallback: false, attendedFile: true },
|
|
12039
|
+
metal: { vault: false, systemdFallback: true, attendedFile: false },
|
|
12040
|
+
"platform-compute": { vault: true, systemdFallback: true, attendedFile: false },
|
|
12041
|
+
"tenant-compute": { vault: true, systemdFallback: true, attendedFile: false }
|
|
12042
|
+
};
|
|
12043
|
+
var CREDENTIAL_NAME = /^[A-Z_][A-Z0-9_]*$/;
|
|
12044
|
+
var SCOPE_PART2 = /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/;
|
|
12045
|
+
function deploymentCredentialSchema(input) {
|
|
12046
|
+
if (!SCOPE_PART2.test(input.projectKey) || !SCOPE_PART2.test(input.environmentKey)) {
|
|
12047
|
+
throw new Error("agent: deployment credential scope is malformed");
|
|
12048
|
+
}
|
|
12049
|
+
const systemd = [...new Set(input.systemdCredentials ?? [])].sort();
|
|
12050
|
+
for (const name of systemd) {
|
|
12051
|
+
if (!CREDENTIAL_NAME.test(name)) {
|
|
12052
|
+
throw new Error(`agent: invalid pipeline credential name ${name}.`);
|
|
12053
|
+
}
|
|
12054
|
+
}
|
|
12055
|
+
return {
|
|
12056
|
+
version: 1,
|
|
12057
|
+
location: input.realm === "platform" ? "platform-compute" : "tenant-compute",
|
|
12058
|
+
projectKey: input.projectKey,
|
|
12059
|
+
environmentKey: input.environmentKey,
|
|
12060
|
+
credentials: systemd.map((name) => ({
|
|
12061
|
+
name,
|
|
12062
|
+
vaultCacheKey: projectVaultCacheKey({ environment: input.environmentKey, name }),
|
|
12063
|
+
systemdCredential: name
|
|
12064
|
+
}))
|
|
12065
|
+
};
|
|
12066
|
+
}
|
|
12067
|
+
function credentialBinding(schema, name) {
|
|
12068
|
+
if (!CREDENTIAL_NAME.test(name))
|
|
12069
|
+
throw new Error(`agent: invalid pipeline credential name ${name}.`);
|
|
12070
|
+
const declared = schema.credentials.find((entry) => entry.name === name);
|
|
12071
|
+
return declared ?? {
|
|
12072
|
+
name,
|
|
12073
|
+
vaultCacheKey: projectVaultCacheKey({ environment: schema.environmentKey, name })
|
|
12074
|
+
};
|
|
12075
|
+
}
|
|
12076
|
+
var METAL_SYSTEMD_CREDENTIALS = {
|
|
12077
|
+
identity: "metal-agent-seed"
|
|
12078
|
+
};
|
|
12079
|
+
|
|
11964
12080
|
// src/index.ts
|
|
11965
12081
|
function loadOrCreateSeed(path) {
|
|
11966
12082
|
if (existsSync13(path)) {
|
|
@@ -12036,6 +12152,31 @@ function createSystemdDeploymentSecrets(names, directory = process.env.CREDENTIA
|
|
|
12036
12152
|
}
|
|
12037
12153
|
};
|
|
12038
12154
|
}
|
|
12155
|
+
function createDeploymentSecretResolver(schema, primary, fallback) {
|
|
12156
|
+
if (!primary)
|
|
12157
|
+
return fallback;
|
|
12158
|
+
return {
|
|
12159
|
+
async get(name) {
|
|
12160
|
+
const binding = credentialBinding(schema, name);
|
|
12161
|
+
try {
|
|
12162
|
+
return await primary.get(binding.vaultCacheKey);
|
|
12163
|
+
} catch (cause) {
|
|
12164
|
+
if (binding.systemdCredential && fallback?.has(binding.systemdCredential)) {
|
|
12165
|
+
return fallback.get(binding.systemdCredential);
|
|
12166
|
+
}
|
|
12167
|
+
throw cause;
|
|
12168
|
+
}
|
|
12169
|
+
}
|
|
12170
|
+
};
|
|
12171
|
+
}
|
|
12172
|
+
async function initializeVaultReplica(cache) {
|
|
12173
|
+
try {
|
|
12174
|
+
const result = await cache.load();
|
|
12175
|
+
return result.failed.length === 0 ? { state: "ready", loaded: result.loaded, failed: result.failed } : { state: "partial", loaded: result.loaded, failed: result.failed };
|
|
12176
|
+
} catch {
|
|
12177
|
+
return { state: "unavailable", loaded: 0, failed: [] };
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12039
12180
|
function runAgent(config = {}) {
|
|
12040
12181
|
const seed = config.seed ?? configuredAgentSeed({
|
|
12041
12182
|
credential: config.seedCredential,
|
|
@@ -12043,6 +12184,7 @@ function runAgent(config = {}) {
|
|
|
12043
12184
|
allowFileSeed: config.allowFileSeed
|
|
12044
12185
|
});
|
|
12045
12186
|
const keys = deriveKeysFromSeed(seed);
|
|
12187
|
+
seed.fill(0);
|
|
12046
12188
|
const nodeKey = config.nodeKey ?? keys.ed25519.publicKey;
|
|
12047
12189
|
const options = {
|
|
12048
12190
|
socketPath: config.socketPath ?? DEFAULT_SOCKET_PATH,
|
|
@@ -12110,6 +12252,7 @@ if (import.meta.main) {
|
|
|
12110
12252
|
allowFileSeed
|
|
12111
12253
|
});
|
|
12112
12254
|
const keys2 = deriveKeysFromSeed(seed);
|
|
12255
|
+
seed.fill(0);
|
|
12113
12256
|
console.log(JSON.stringify({
|
|
12114
12257
|
nodeKey: keys2.ed25519.publicKey,
|
|
12115
12258
|
publicKeys: { ed25519: keys2.ed25519.publicKey, mlDsa: keys2.mlDsa.publicKey }
|
|
@@ -12128,6 +12271,7 @@ if (import.meta.main) {
|
|
|
12128
12271
|
allowFileSeed
|
|
12129
12272
|
});
|
|
12130
12273
|
const keys2 = deriveKeysFromSeed(seed);
|
|
12274
|
+
seed.fill(0);
|
|
12131
12275
|
const nodeKey2 = process.env.FZ_NODE_KEY ?? keys2.ed25519.publicKey;
|
|
12132
12276
|
const binding2 = await enrolGuestIdentity({
|
|
12133
12277
|
apiUrl: process.env.FZ_API,
|
|
@@ -12358,6 +12502,7 @@ if (import.meta.main) {
|
|
|
12358
12502
|
allowFileSeed
|
|
12359
12503
|
});
|
|
12360
12504
|
const keys2 = deriveKeysFromSeed(seed);
|
|
12505
|
+
seed.fill(0);
|
|
12361
12506
|
const nodeKey2 = process.env.FZ_NODE_KEY ?? keys2.ed25519.publicKey;
|
|
12362
12507
|
const pull = startProvisioningPull({
|
|
12363
12508
|
apiUrl: process.env.FZ_API,
|
|
@@ -12496,23 +12641,26 @@ if (import.meta.main) {
|
|
|
12496
12641
|
}));
|
|
12497
12642
|
console.log(`[agent] initial SEV-SNP attestation verified ${result.measurement.slice(0, 16)}\u2026`);
|
|
12498
12643
|
}
|
|
12499
|
-
if (binding
|
|
12644
|
+
if (binding && nodeApiUrl) {
|
|
12500
12645
|
secretCache = createNodeVaultCache({
|
|
12501
12646
|
apiUrl: nodeApiUrl,
|
|
12502
12647
|
nodeKey,
|
|
12503
12648
|
keys,
|
|
12504
12649
|
projectKey: binding.projectKey
|
|
12505
12650
|
});
|
|
12506
|
-
const
|
|
12507
|
-
if (loaded.failed.length > 0) {
|
|
12508
|
-
throw new Error(`agent: failed to load ${loaded.failed.length} assigned vault entries`);
|
|
12509
|
-
}
|
|
12651
|
+
const initialVault = await telemetry.observe("vault.sync", () => initializeVaultReplica(secretCache), (result) => result.state === "ready" ? "success" : "failed");
|
|
12510
12652
|
running.setVault(secretCache, binding.projectKey);
|
|
12511
12653
|
vaultSync = startNodeVaultSync(secretCache, {
|
|
12512
12654
|
telemetry,
|
|
12513
12655
|
onEvent: (event, detail) => console.log(`[agent] vault ${event}${detail ? ` ${JSON.stringify(detail)}` : ""}`)
|
|
12514
12656
|
});
|
|
12515
|
-
|
|
12657
|
+
if (initialVault.state === "ready") {
|
|
12658
|
+
console.log(`[agent] in-memory vault loaded for every environment in project ${binding.projectKey}`);
|
|
12659
|
+
} else if (initialVault.state === "partial") {
|
|
12660
|
+
console.error(`[agent] vault replica partial (${initialVault.loaded} loaded, ${initialVault.failed.length} unavailable); ` + "explicit same-name systemd deployment fallbacks remain available");
|
|
12661
|
+
} else {
|
|
12662
|
+
console.error("[agent] vault replica unavailable; authenticated refresh remains active and only explicit " + "same-name systemd deployment fallbacks are available");
|
|
12663
|
+
}
|
|
12516
12664
|
}
|
|
12517
12665
|
const attestationLoop = attestationSource && nodeApiUrl ? startNodeAttestation({
|
|
12518
12666
|
apiUrl: nodeApiUrl,
|
|
@@ -12557,17 +12705,14 @@ if (import.meta.main) {
|
|
|
12557
12705
|
if (bootstrapPull)
|
|
12558
12706
|
console.log("[agent] PQ-authenticated delegated SSH bootstrap claims enabled");
|
|
12559
12707
|
const systemdDeploymentSecrets = createSystemdDeploymentSecrets(process.env.FZ_DEPLOY_SYSTEMD_SECRETS);
|
|
12560
|
-
const
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
}
|
|
12569
|
-
}
|
|
12570
|
-
} : systemdDeploymentSecrets;
|
|
12708
|
+
const deploymentCredentialNames = (process.env.FZ_DEPLOY_SYSTEMD_SECRETS ?? "").split(",").map((name) => name.trim()).filter(Boolean);
|
|
12709
|
+
const deploymentSchema = binding ? deploymentCredentialSchema({
|
|
12710
|
+
realm: binding.realm,
|
|
12711
|
+
projectKey: binding.projectKey,
|
|
12712
|
+
environmentKey: binding.environmentKey,
|
|
12713
|
+
systemdCredentials: deploymentCredentialNames
|
|
12714
|
+
}) : undefined;
|
|
12715
|
+
const deploymentSecrets = deploymentSchema ? createDeploymentSecretResolver(deploymentSchema, secretCache, systemdDeploymentSecrets) : systemdDeploymentSecrets;
|
|
12571
12716
|
const repository = process.env.FZ_DEPLOY_REPO;
|
|
12572
12717
|
const branch = process.env.FZ_DEPLOY_BRANCH;
|
|
12573
12718
|
const profile = process.env.FZ_DEPLOY_PROFILE;
|
|
@@ -12835,6 +12980,7 @@ export {
|
|
|
12835
12980
|
loadOrCreateSeed,
|
|
12836
12981
|
loadLifecycleProfile,
|
|
12837
12982
|
loadGuestBinding,
|
|
12983
|
+
initializeVaultReplica,
|
|
12838
12984
|
heartbeatAgentOnce,
|
|
12839
12985
|
handleRequest,
|
|
12840
12986
|
handleApplicationRequest,
|
|
@@ -12843,10 +12989,13 @@ export {
|
|
|
12843
12989
|
executeLifecycleAction,
|
|
12844
12990
|
ensureSoftwareRequirements,
|
|
12845
12991
|
enrolGuestIdentity,
|
|
12992
|
+
deploymentCredentialSchema,
|
|
12993
|
+
credentialBinding,
|
|
12846
12994
|
createSystemdDeploymentSecrets,
|
|
12847
12995
|
createSnpAttestationSource,
|
|
12848
12996
|
createSecretCache,
|
|
12849
12997
|
createNodeVaultCache,
|
|
12998
|
+
createDeploymentSecretResolver,
|
|
12850
12999
|
createDeploymentManager,
|
|
12851
13000
|
createAgentTelemetry,
|
|
12852
13001
|
configuredAgentSeed,
|
|
@@ -12868,6 +13017,7 @@ export {
|
|
|
12868
13017
|
SOFTWARE_HELPER_GROUP,
|
|
12869
13018
|
SOFTWARE_CATALOG,
|
|
12870
13019
|
OS_CATALOG,
|
|
13020
|
+
METAL_SYSTEMD_CREDENTIALS,
|
|
12871
13021
|
MAX_AGENT_TARBALL_BYTES,
|
|
12872
13022
|
DeploymentError,
|
|
12873
13023
|
DEFAULT_SOFTWARE_HELPER_SOCKET,
|
|
@@ -12891,5 +13041,7 @@ export {
|
|
|
12891
13041
|
AGENT_TELEMETRY_OUTCOMES,
|
|
12892
13042
|
AGENT_TELEMETRY_OPERATIONS,
|
|
12893
13043
|
AGENT_TELEMETRY_EVENTS,
|
|
12894
|
-
AGENT_EGRESS_TABLE
|
|
13044
|
+
AGENT_EGRESS_TABLE,
|
|
13045
|
+
AGENT_CREDENTIAL_POLICY,
|
|
13046
|
+
AGENT_CREDENTIAL_LOCATIONS
|
|
12895
13047
|
};
|