@odla-ai/cli 0.29.0 → 0.30.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/README.md +42 -23
- package/dist/bin.cjs +254 -43
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-YTVLTADT.js → chunk-PPSXHZJI.js} +234 -44
- package/dist/chunk-PPSXHZJI.js.map +1 -0
- package/dist/{cli-DNOAYDBR.js → cli-CKBUVTJM.js} +2 -2
- package/dist/index.cjs +233 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/runtime/pi-agent.js +18728 -15
- package/package.json +1 -1
- package/skills/odla/SKILL.md +4 -1
- package/skills/odla/references/pm-work-intake.md +5 -3
- package/skills/odla/references/pm.md +4 -0
- package/skills/odla-migrate/references/secrets-map.md +22 -22
- package/skills/odla-migrate/references/troubleshooting.md +14 -16
- package/dist/chunk-YTVLTADT.js.map +0 -1
- /package/dist/{cli-DNOAYDBR.js.map → cli-CKBUVTJM.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-CKBUVTJM.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -3831,6 +3831,41 @@ async function wranglerLoggedIn(run, cwd) {
|
|
|
3831
3831
|
return false;
|
|
3832
3832
|
}
|
|
3833
3833
|
}
|
|
3834
|
+
async function wranglerRuntimeTarget(run, opts) {
|
|
3835
|
+
const configPath = findWranglerConfig(opts.cwd);
|
|
3836
|
+
if (!configPath) throw new Error(`no wrangler config found in ${opts.cwd}`);
|
|
3837
|
+
const config = readWranglerConfig(configPath);
|
|
3838
|
+
if (!config) throw new Error("runtime credential delivery requires wrangler.json or wrangler.jsonc");
|
|
3839
|
+
const baseName = typeof config.name === "string" ? config.name : "";
|
|
3840
|
+
const envs = config.env && typeof config.env === "object" && !Array.isArray(config.env) ? config.env : {};
|
|
3841
|
+
const envConfig = opts.env && envs[opts.env] && typeof envs[opts.env] === "object" ? envs[opts.env] : {};
|
|
3842
|
+
const explicitName = typeof envConfig.name === "string" ? envConfig.name : "";
|
|
3843
|
+
const serviceEnvironments = config.legacy_env === false;
|
|
3844
|
+
if (serviceEnvironments && explicitName) {
|
|
3845
|
+
throw new Error("env.<name>.name is not allowed when wrangler legacy_env is false");
|
|
3846
|
+
}
|
|
3847
|
+
const scriptName = serviceEnvironments ? baseName : explicitName || (opts.env ? `${baseName}-${opts.env}` : baseName);
|
|
3848
|
+
if (!/^[a-z0-9][a-z0-9_-]{0,62}$/.test(scriptName)) {
|
|
3849
|
+
throw new Error("wrangler config must resolve an exact Worker name before credentials are issued");
|
|
3850
|
+
}
|
|
3851
|
+
const configuredAccount = typeof envConfig.account_id === "string" ? envConfig.account_id : typeof config.account_id === "string" ? config.account_id : "";
|
|
3852
|
+
const whoami = await run("npx", ["wrangler", "whoami"], { cwd: opts.cwd });
|
|
3853
|
+
if (whoami.code !== 0 || /not authenticated/i.test(`${whoami.stdout}${whoami.stderr}`)) {
|
|
3854
|
+
throw new Error(`wrangler is not logged in \u2014 run "wrangler login" (a browser step for the human)`);
|
|
3855
|
+
}
|
|
3856
|
+
const discovered = [...new Set(`${whoami.stdout}
|
|
3857
|
+
${whoami.stderr}`.match(/\b[a-f0-9]{32}\b/gi)?.map((id) => id.toLowerCase()) ?? [])];
|
|
3858
|
+
const accountId = configuredAccount.toLowerCase() || (discovered.length === 1 ? discovered[0] : "");
|
|
3859
|
+
if (!/^[a-f0-9]{32}$/.test(accountId) || configuredAccount && discovered.length > 0 && !discovered.includes(accountId)) {
|
|
3860
|
+
throw new Error("Wrangler account is ambiguous or does not match account_id in the config");
|
|
3861
|
+
}
|
|
3862
|
+
return {
|
|
3863
|
+
provider: "cloudflare",
|
|
3864
|
+
accountId,
|
|
3865
|
+
scriptName,
|
|
3866
|
+
...opts.env ? { environment: opts.env } : {}
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3834
3869
|
function wranglerPutSecret(run, opts) {
|
|
3835
3870
|
const args = [
|
|
3836
3871
|
"wrangler",
|
|
@@ -3842,6 +3877,16 @@ function wranglerPutSecret(run, opts) {
|
|
|
3842
3877
|
];
|
|
3843
3878
|
return run("npx", args, { input: opts.value, cwd: opts.cwd });
|
|
3844
3879
|
}
|
|
3880
|
+
function wranglerBulkSecrets(run, opts) {
|
|
3881
|
+
const args = [
|
|
3882
|
+
"wrangler",
|
|
3883
|
+
"secret",
|
|
3884
|
+
"bulk",
|
|
3885
|
+
...opts.env ? ["--env", opts.env] : [],
|
|
3886
|
+
...opts.configPath ? ["--config", opts.configPath] : []
|
|
3887
|
+
];
|
|
3888
|
+
return run("npx", args, { input: JSON.stringify(opts.secrets), cwd: opts.cwd });
|
|
3889
|
+
}
|
|
3845
3890
|
|
|
3846
3891
|
// src/doctor-checks.ts
|
|
3847
3892
|
function lintRules(rules, entities, publicRead) {
|
|
@@ -4330,9 +4375,6 @@ var PROD_ENV_NAMES = /* @__PURE__ */ new Set(["prod", "production"]);
|
|
|
4330
4375
|
async function secretsPush(options) {
|
|
4331
4376
|
await secretsPushImpl(options, true);
|
|
4332
4377
|
}
|
|
4333
|
-
async function secretsPushAfterPreflight(options) {
|
|
4334
|
-
await secretsPushImpl(options, false);
|
|
4335
|
-
}
|
|
4336
4378
|
async function secretsPushImpl(options, preflight) {
|
|
4337
4379
|
const out = options.stdout ?? console;
|
|
4338
4380
|
const cfg = await loadProjectConfig(options.configPath);
|
|
@@ -8697,6 +8739,55 @@ function requireName(parsed) {
|
|
|
8697
8739
|
return name;
|
|
8698
8740
|
}
|
|
8699
8741
|
|
|
8742
|
+
// src/credential-command.ts
|
|
8743
|
+
async function responseError(response2) {
|
|
8744
|
+
return redactSecrets((await response2.text()).slice(0, 1e3));
|
|
8745
|
+
}
|
|
8746
|
+
async function credentialCommand(parsed, deps = {}) {
|
|
8747
|
+
const action2 = parsed.positionals[1] ?? "list";
|
|
8748
|
+
if (action2 !== "list" && action2 !== "revoke") {
|
|
8749
|
+
throw new Error(`unknown credentials action "${action2}". Try "odla-ai credentials list".`);
|
|
8750
|
+
}
|
|
8751
|
+
assertArgs(parsed, ["config", "env", "all", "json", "token", "email", "open"], action2 === "revoke" ? 3 : 2);
|
|
8752
|
+
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
8753
|
+
const doFetch = deps.fetch ?? fetch;
|
|
8754
|
+
const out = deps.stdout ?? console;
|
|
8755
|
+
const token = await getDeveloperToken(cfg, {
|
|
8756
|
+
configPath: cfg.configPath,
|
|
8757
|
+
token: stringOpt(parsed.options.token),
|
|
8758
|
+
email: stringOpt(parsed.options.email),
|
|
8759
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
8760
|
+
openApprovalUrl: deps.openUrl
|
|
8761
|
+
}, doFetch, out, { optionalProjectCapabilities: ["app.manage"] });
|
|
8762
|
+
const base = `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials`;
|
|
8763
|
+
if (action2 === "revoke") {
|
|
8764
|
+
const id = parsed.positionals[2];
|
|
8765
|
+
if (!id) throw new Error("credentials revoke requires the exact receipt id from credentials list");
|
|
8766
|
+
const response3 = await doFetch(`${base}/${encodeURIComponent(id)}`, {
|
|
8767
|
+
method: "DELETE",
|
|
8768
|
+
headers: { authorization: `Bearer ${token}` }
|
|
8769
|
+
});
|
|
8770
|
+
if (!response3.ok) throw new Error(`runtime credential revoke failed (${response3.status}): ${await responseError(response3)}`);
|
|
8771
|
+
const body2 = await response3.json();
|
|
8772
|
+
return out.log(parsed.options.json === true ? JSON.stringify(body2, null, 2) : `revoked ${body2.receipt.id} (${body2.receipt.env} ${body2.receipt.target.scriptName})`);
|
|
8773
|
+
}
|
|
8774
|
+
const query = new URLSearchParams();
|
|
8775
|
+
const requestedEnv = stringOpt(parsed.options.env);
|
|
8776
|
+
if (requestedEnv) query.set("env", requestedEnv);
|
|
8777
|
+
const response2 = await doFetch(`${base}${query.size ? `?${query}` : ""}`, {
|
|
8778
|
+
headers: { authorization: `Bearer ${token}` }
|
|
8779
|
+
});
|
|
8780
|
+
if (!response2.ok) throw new Error(`runtime credential inventory failed (${response2.status}): ${await responseError(response2)}`);
|
|
8781
|
+
const body = await response2.json();
|
|
8782
|
+
const credentials = parsed.options.all === true ? body.credentials : body.credentials.filter((item) => item.state === "committed");
|
|
8783
|
+
if (parsed.options.json === true) return out.log(JSON.stringify({ credentials }, null, 2));
|
|
8784
|
+
if (!credentials.length) return out.log("no active runtime credential receipts");
|
|
8785
|
+
out.log("RECEIPT ENV TARGET CREATED");
|
|
8786
|
+
for (const item of credentials) {
|
|
8787
|
+
out.log(`${item.id} ${item.env} ${item.target.accountId ?? "local"}/${item.target.scriptName} ${new Date(item.createdAt).toISOString()}`);
|
|
8788
|
+
}
|
|
8789
|
+
}
|
|
8790
|
+
|
|
8700
8791
|
// src/help-usage.ts
|
|
8701
8792
|
var USAGE_SECTION = `
|
|
8702
8793
|
Start here:
|
|
@@ -8815,6 +8906,8 @@ Usage:
|
|
|
8815
8906
|
odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
|
|
8816
8907
|
odla-ai security run [target] --self --ack-redacted-source
|
|
8817
8908
|
odla-ai provision [--live] [--config odla.config.mjs] [--email <odla-account>] [--request-grant] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
8909
|
+
odla-ai credentials list [--config odla.config.mjs] [--env dev] [--all] [--json]
|
|
8910
|
+
odla-ai credentials revoke <receipt-id> [--config odla.config.mjs] [--json]
|
|
8818
8911
|
odla-ai smoke [--config odla.config.mjs] [--env dev] [--email <odla-account>] [--no-open]
|
|
8819
8912
|
odla-ai skill install [--dir <project>] [--agent <name>] [--global] [--force]
|
|
8820
8913
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
@@ -8937,9 +9030,13 @@ Safety:
|
|
|
8937
9030
|
pinned versions of every external @odla-ai runtime module before importing
|
|
8938
9031
|
the command graph. A stale workspace module blocks with its resolved path and
|
|
8939
9032
|
tells the agent to update/rebase, npm ci, and rebuild.
|
|
8940
|
-
Provision caches the approved developer token
|
|
8941
|
-
|
|
8942
|
-
|
|
9033
|
+
Provision caches the approved developer token under .odla/ with mode 0600.
|
|
9034
|
+
Local-only development provisioning may also cache that developer's service
|
|
9035
|
+
credentials there. \`provision --push-secrets\` instead stages a fresh,
|
|
9036
|
+
independently revocable credential set through the approved handshake,
|
|
9037
|
+
transfers the complete set to the exact Worker with \`wrangler secret bulk\`
|
|
9038
|
+
over stdin, and never writes its plaintext under .odla. Secret push preflights
|
|
9039
|
+
Wrangler before shown-once issuance; it never rotates sibling credentials.
|
|
8943
9040
|
Projectless PM, Discussions, o11y, runbook, and identity commands use
|
|
8944
9041
|
--platform/--app/--env, ODLA_PLATFORM_URL/ODLA_APP_ID/ODLA_ENV, and
|
|
8945
9042
|
ODLA_DEV_TOKEN. Save non-secret scope metadata with "context save", then
|
|
@@ -10863,7 +10960,7 @@ async function issueO11yToken(opts) {
|
|
|
10863
10960
|
);
|
|
10864
10961
|
if (res.status === 409 && !opts.rotateO11y) {
|
|
10865
10962
|
throw new Error(
|
|
10866
|
-
`o11y token already exists for env "${opts.env}", but its shown-once value is not in the local credentials file; run "odla-ai provision --
|
|
10963
|
+
`o11y token already exists for env "${opts.env}", but its shown-once value is not in the local credentials file; run "odla-ai provision --push-secrets" to install a separate runtime credential without rotating siblings`
|
|
10867
10964
|
);
|
|
10868
10965
|
}
|
|
10869
10966
|
if (!res.ok) throw new Error(`o11y token ${opts.rotateO11y ? "rotation" : "issue"} (${opts.env}) failed: ${res.status} ${await safeText7(res)}`);
|
|
@@ -10879,6 +10976,88 @@ async function safeText7(res) {
|
|
|
10879
10976
|
}
|
|
10880
10977
|
}
|
|
10881
10978
|
|
|
10979
|
+
// src/runtime-credentials.ts
|
|
10980
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
10981
|
+
function runtimeUrl(cfg, suffix = "") {
|
|
10982
|
+
return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
|
|
10983
|
+
}
|
|
10984
|
+
async function safeError(response2) {
|
|
10985
|
+
const text2 = await response2.text();
|
|
10986
|
+
return redactSecrets(text2.slice(0, 1e3));
|
|
10987
|
+
}
|
|
10988
|
+
async function finish(doFetch, cfg, token, sessionId, method) {
|
|
10989
|
+
return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
|
|
10990
|
+
method,
|
|
10991
|
+
headers: { authorization: `Bearer ${token}` }
|
|
10992
|
+
});
|
|
10993
|
+
}
|
|
10994
|
+
async function deliverRuntimeCredentials(cfg, options) {
|
|
10995
|
+
const doFetch = options.fetch ?? fetch;
|
|
10996
|
+
const run = options.runner ?? defaultRunner;
|
|
10997
|
+
const wranglerEnv = options.env === "prod" || options.env === "production" ? void 0 : options.env;
|
|
10998
|
+
const target = await wranglerRuntimeTarget(run, {
|
|
10999
|
+
cwd: cfg.rootDir,
|
|
11000
|
+
env: wranglerEnv
|
|
11001
|
+
});
|
|
11002
|
+
const issue = await doFetch(runtimeUrl(cfg), {
|
|
11003
|
+
method: "POST",
|
|
11004
|
+
headers: {
|
|
11005
|
+
authorization: `Bearer ${options.developerToken}`,
|
|
11006
|
+
"content-type": "application/json"
|
|
11007
|
+
},
|
|
11008
|
+
body: JSON.stringify({
|
|
11009
|
+
env: options.env,
|
|
11010
|
+
idempotencyKey: `wrangler:${randomUUID3()}`,
|
|
11011
|
+
target
|
|
11012
|
+
})
|
|
11013
|
+
});
|
|
11014
|
+
const body = await issue.json().catch(() => null);
|
|
11015
|
+
if (!issue.ok || typeof body?.sessionId !== "string" || !body.secrets || typeof body.secrets !== "object") {
|
|
11016
|
+
const detail = body?.error?.code ?? body?.error?.message ?? issue.status;
|
|
11017
|
+
throw new Error(`runtime credential staging failed: ${String(detail)}`);
|
|
11018
|
+
}
|
|
11019
|
+
const secrets = body.secrets;
|
|
11020
|
+
const values = {};
|
|
11021
|
+
for (const name of ["ODLA_API_KEY", "ODLA_O11Y_TOKEN"]) {
|
|
11022
|
+
const value2 = secrets[name];
|
|
11023
|
+
if (typeof value2 === "string" && value2) values[name] = value2;
|
|
11024
|
+
}
|
|
11025
|
+
if (Object.keys(values).length === 0) {
|
|
11026
|
+
await finish(doFetch, cfg, options.developerToken, body.sessionId, "DELETE");
|
|
11027
|
+
throw new Error("runtime credential staging returned no configured service credentials");
|
|
11028
|
+
}
|
|
11029
|
+
const pushed = await wranglerBulkSecrets(run, {
|
|
11030
|
+
secrets: values,
|
|
11031
|
+
env: wranglerEnv,
|
|
11032
|
+
cwd: cfg.rootDir
|
|
11033
|
+
});
|
|
11034
|
+
if (pushed.code !== 0) {
|
|
11035
|
+
await finish(doFetch, cfg, options.developerToken, body.sessionId, "DELETE");
|
|
11036
|
+
const detail = redactSecrets(`${pushed.stderr || pushed.stdout}`.trim());
|
|
11037
|
+
throw new Error(`wrangler secret bulk failed (exit ${pushed.code}): ${detail}`);
|
|
11038
|
+
}
|
|
11039
|
+
const committed = await finish(
|
|
11040
|
+
doFetch,
|
|
11041
|
+
cfg,
|
|
11042
|
+
options.developerToken,
|
|
11043
|
+
body.sessionId,
|
|
11044
|
+
"POST"
|
|
11045
|
+
);
|
|
11046
|
+
if (!committed.ok) {
|
|
11047
|
+
await finish(doFetch, cfg, options.developerToken, body.sessionId, "DELETE");
|
|
11048
|
+
throw new Error(`runtime credential receipt commit failed: ${await safeError(committed)}`);
|
|
11049
|
+
}
|
|
11050
|
+
options.stdout?.log(
|
|
11051
|
+
`${options.env}: installed ${Object.keys(values).join(" + ")} on ${target.accountId}/${target.scriptName}${target.environment ? ` (${target.environment})` : ""}; plaintext stayed in memory`
|
|
11052
|
+
);
|
|
11053
|
+
return {
|
|
11054
|
+
sessionId: body.sessionId,
|
|
11055
|
+
target,
|
|
11056
|
+
...values.ODLA_API_KEY ? { dbKey: values.ODLA_API_KEY } : {},
|
|
11057
|
+
...values.ODLA_O11Y_TOKEN ? { o11yToken: values.ODLA_O11Y_TOKEN } : {}
|
|
11058
|
+
};
|
|
11059
|
+
}
|
|
11060
|
+
|
|
10882
11061
|
// src/provision-live.ts
|
|
10883
11062
|
function liveProvisionConfig(cfg) {
|
|
10884
11063
|
if (!cfg.envs.includes("dev")) {
|
|
@@ -10912,8 +11091,10 @@ async function provision(options) {
|
|
|
10912
11091
|
if (options.rotateO11yToken && !hasO11y) {
|
|
10913
11092
|
throw new Error("--rotate-o11y-token requires the o11y service in odla.config.mjs");
|
|
10914
11093
|
}
|
|
10915
|
-
if (options.pushSecrets && options.
|
|
10916
|
-
throw new Error(
|
|
11094
|
+
if (options.pushSecrets && (options.rotateKeys || options.rotateO11yToken)) {
|
|
11095
|
+
throw new Error(
|
|
11096
|
+
"--push-secrets always issues an independent runtime credential set; do not combine it with destructive rotation flags"
|
|
11097
|
+
);
|
|
10917
11098
|
}
|
|
10918
11099
|
out.log(`odla-ai: ${plan.appName} (${plan.appId})`);
|
|
10919
11100
|
out.log(` platform: ${plan.platformUrl}`);
|
|
@@ -10950,7 +11131,7 @@ async function provision(options) {
|
|
|
10950
11131
|
out.log(` secrets: ${options.pushSecrets ? "push configured Worker secrets" : "local only"}`);
|
|
10951
11132
|
return;
|
|
10952
11133
|
}
|
|
10953
|
-
let credentials = readCredentials(cfg.local.credentialsFile);
|
|
11134
|
+
let credentials = options.pushSecrets ? null : readCredentials(cfg.local.credentialsFile);
|
|
10954
11135
|
if (credentials && credentials.appId !== cfg.app.id) {
|
|
10955
11136
|
throw new Error(
|
|
10956
11137
|
`credentials at ${displayPath(cfg.local.credentialsFile, cfg.rootDir)} are for "${credentials.appId}", not "${cfg.app.id}"`
|
|
@@ -10959,7 +11140,7 @@ async function provision(options) {
|
|
|
10959
11140
|
const rotatesO11y = !!(options.rotateKeys || options.rotateO11yToken);
|
|
10960
11141
|
const missingO11y = cfg.envs.some((env) => !credentials?.envs[env]?.o11yToken);
|
|
10961
11142
|
const missingDb = cfg.envs.some((env) => !credentials?.envs[env]?.dbKey);
|
|
10962
|
-
const losesShownOnceCredential = hasDb && (!!options.rotateKeys || missingDb) || hasO11y && (rotatesO11y || missingO11y);
|
|
11143
|
+
const losesShownOnceCredential = !options.pushSecrets && (hasDb && (!!options.rotateKeys || missingDb) || hasO11y && (rotatesO11y || missingO11y));
|
|
10963
11144
|
if (options.writeCredentials === false && losesShownOnceCredential) {
|
|
10964
11145
|
throw new Error("credential issuance/rotation requires the private credentials file; remove --no-write-credentials");
|
|
10965
11146
|
}
|
|
@@ -11033,38 +11214,42 @@ async function provision(options) {
|
|
|
11033
11214
|
await applyCalendarBookingPage(calendarCtx, calendarBookingPageUrl(cfg, env), out);
|
|
11034
11215
|
}
|
|
11035
11216
|
}
|
|
11217
|
+
let devVarsCredentials = credentials;
|
|
11036
11218
|
for (const env of cfg.envs) {
|
|
11037
11219
|
const tenantId = tenantIdFor5(cfg.app.id, env);
|
|
11038
|
-
|
|
11039
|
-
cfg,
|
|
11040
|
-
env,
|
|
11041
|
-
developerToken: token,
|
|
11042
|
-
credentials,
|
|
11043
|
-
rotateDb: !!options.rotateKeys,
|
|
11044
|
-
rotateO11y: rotatesO11y,
|
|
11045
|
-
write: options.writeCredentials !== false,
|
|
11046
|
-
fetch: doFetch,
|
|
11047
|
-
stdout: out
|
|
11048
|
-
});
|
|
11049
|
-
const dbKey = credentials.envs[env]?.dbKey;
|
|
11220
|
+
let dbKey;
|
|
11050
11221
|
if (options.pushSecrets) {
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
}
|
|
11222
|
+
const delivered = await deliverRuntimeCredentials(cfg, {
|
|
11223
|
+
env,
|
|
11224
|
+
developerToken: token,
|
|
11225
|
+
fetch: doFetch,
|
|
11226
|
+
runner: options.secretRunner,
|
|
11227
|
+
stdout: out
|
|
11228
|
+
});
|
|
11229
|
+
dbKey = delivered.dbKey;
|
|
11230
|
+
devVarsCredentials = mergeCredential(devVarsCredentials, {
|
|
11231
|
+
appId: cfg.app.id,
|
|
11232
|
+
platformUrl: cfg.platformUrl,
|
|
11233
|
+
dbEndpoint: cfg.dbEndpoint,
|
|
11234
|
+
env,
|
|
11235
|
+
tenantId,
|
|
11236
|
+
...delivered.dbKey ? { dbKey: delivered.dbKey } : {},
|
|
11237
|
+
...delivered.o11yToken ? { o11yToken: delivered.o11yToken } : {}
|
|
11238
|
+
});
|
|
11239
|
+
} else {
|
|
11240
|
+
credentials = await provisionEnvCredentials({
|
|
11241
|
+
cfg,
|
|
11242
|
+
env,
|
|
11243
|
+
developerToken: token,
|
|
11244
|
+
credentials,
|
|
11245
|
+
rotateDb: !!options.rotateKeys,
|
|
11246
|
+
rotateO11y: rotatesO11y,
|
|
11247
|
+
write: options.writeCredentials !== false,
|
|
11248
|
+
fetch: doFetch,
|
|
11249
|
+
stdout: out
|
|
11250
|
+
});
|
|
11251
|
+
devVarsCredentials = credentials;
|
|
11252
|
+
dbKey = credentials.envs[env]?.dbKey;
|
|
11068
11253
|
}
|
|
11069
11254
|
if (schema && dbKey) {
|
|
11070
11255
|
await postJson(doFetch, `${cfg.dbEndpoint}/app/${encodeURIComponent(tenantId)}/schema`, dbKey, { schema });
|
|
@@ -11088,13 +11273,13 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
|
|
|
11088
11273
|
}
|
|
11089
11274
|
}
|
|
11090
11275
|
}
|
|
11091
|
-
if (options.writeCredentials !== false && credentials) {
|
|
11276
|
+
if (!options.pushSecrets && options.writeCredentials !== false && credentials) {
|
|
11092
11277
|
const ignored = cfg.local.gitignore && gitignoreEntry(cfg.rootDir, cfg.local.credentialsFile);
|
|
11093
11278
|
out.log(`credentials: wrote ${displayPath(cfg.local.credentialsFile, cfg.rootDir)} (0600${ignored ? ", gitignored" : ""})`);
|
|
11094
11279
|
}
|
|
11095
|
-
if (devVarsTarget &&
|
|
11280
|
+
if (devVarsTarget && devVarsCredentials) {
|
|
11096
11281
|
const env = cfg.envs.includes("dev") ? "dev" : cfg.envs[0] ?? "prod";
|
|
11097
|
-
writeDevVars(devVarsTarget,
|
|
11282
|
+
writeDevVars(devVarsTarget, devVarsCredentials, env, o11yDevVars(cfg));
|
|
11098
11283
|
out.log(`dev vars: wrote ${displayPath(devVarsTarget, cfg.rootDir)} for ${env}`);
|
|
11099
11284
|
}
|
|
11100
11285
|
if (cfg.services.includes("calendar")) {
|
|
@@ -11185,6 +11370,7 @@ var COMMAND_SURFACE = {
|
|
|
11185
11370
|
code: { connect: {} },
|
|
11186
11371
|
config: { diff: {}, plan: {}, apply: {} },
|
|
11187
11372
|
context: { show: {}, list: {}, save: {}, remove: {} },
|
|
11373
|
+
credentials: { list: {}, revoke: {} },
|
|
11188
11374
|
// `watch`, `read`, `reply`, and `resolve` take a topic id from there on.
|
|
11189
11375
|
discuss: {
|
|
11190
11376
|
groups: {},
|
|
@@ -12869,6 +13055,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
12869
13055
|
await contextCommand(parsed, runtime);
|
|
12870
13056
|
return;
|
|
12871
13057
|
}
|
|
13058
|
+
if (command === "credentials") {
|
|
13059
|
+
await credentialCommand(parsed, runtime);
|
|
13060
|
+
return;
|
|
13061
|
+
}
|
|
12872
13062
|
if (command === "runbook") {
|
|
12873
13063
|
await runbookCommand(parsed, runtime);
|
|
12874
13064
|
return;
|
|
@@ -13056,4 +13246,4 @@ export {
|
|
|
13056
13246
|
isTerminalHostedSecurityStatus,
|
|
13057
13247
|
runCli
|
|
13058
13248
|
};
|
|
13059
|
-
//# sourceMappingURL=chunk-
|
|
13249
|
+
//# sourceMappingURL=chunk-PPSXHZJI.js.map
|