@intentic/cli 1.0.2
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 +21 -0
- package/README.md +80 -0
- package/dist/add-app/add-app.command.d.ts +3 -0
- package/dist/add-app/add-app.command.d.ts.map +1 -0
- package/dist/add-app/add-app.command.js +50 -0
- package/dist/add-app/add-app.command.js.map +1 -0
- package/dist/adopt/adopt.command.d.ts +3 -0
- package/dist/adopt/adopt.command.d.ts.map +1 -0
- package/dist/adopt/adopt.command.js +77 -0
- package/dist/adopt/adopt.command.js.map +1 -0
- package/dist/adopt/adopt.d.ts +21 -0
- package/dist/adopt/adopt.d.ts.map +1 -0
- package/dist/adopt/adopt.js +31 -0
- package/dist/adopt/adopt.js.map +1 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +46 -0
- package/dist/app.js.map +1 -0
- package/dist/apply/access.d.ts +16 -0
- package/dist/apply/access.d.ts.map +1 -0
- package/dist/apply/access.js +72 -0
- package/dist/apply/access.js.map +1 -0
- package/dist/apply/apply-lock.d.ts +12 -0
- package/dist/apply/apply-lock.d.ts.map +1 -0
- package/dist/apply/apply-lock.js +102 -0
- package/dist/apply/apply-lock.js.map +1 -0
- package/dist/apply/apply.command.d.ts +3 -0
- package/dist/apply/apply.command.d.ts.map +1 -0
- package/dist/apply/apply.command.js +144 -0
- package/dist/apply/apply.command.js.map +1 -0
- package/dist/apply/migrate.d.ts +20 -0
- package/dist/apply/migrate.d.ts.map +1 -0
- package/dist/apply/migrate.js +112 -0
- package/dist/apply/migrate.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/demo.d.ts +2 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +281 -0
- package/dist/demo.js.map +1 -0
- package/dist/deployments/deployments.command.d.ts +3 -0
- package/dist/deployments/deployments.command.d.ts.map +1 -0
- package/dist/deployments/deployments.command.js +19 -0
- package/dist/deployments/deployments.command.js.map +1 -0
- package/dist/deployments/deployments.d.ts +14 -0
- package/dist/deployments/deployments.d.ts.map +1 -0
- package/dist/deployments/deployments.js +83 -0
- package/dist/deployments/deployments.js.map +1 -0
- package/dist/env.config.d.ts +25 -0
- package/dist/env.config.d.ts.map +1 -0
- package/dist/env.config.js +31 -0
- package/dist/env.config.js.map +1 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.command.d.ts +3 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.command.d.ts.map +1 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.command.js +39 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.command.js.map +1 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.d.ts +14 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.d.ts.map +1 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.js +21 -0
- package/dist/host-ssh-tunnel/host-ssh-tunnel.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/init/init.command.d.ts +3 -0
- package/dist/init/init.command.d.ts.map +1 -0
- package/dist/init/init.command.js +45 -0
- package/dist/init/init.command.js.map +1 -0
- package/dist/init/init.d.ts +7 -0
- package/dist/init/init.d.ts.map +1 -0
- package/dist/init/init.js +39 -0
- package/dist/init/init.js.map +1 -0
- package/dist/init/scaffold-app.d.ts +2 -0
- package/dist/init/scaffold-app.d.ts.map +1 -0
- package/dist/init/scaffold-app.js +27 -0
- package/dist/init/scaffold-app.js.map +1 -0
- package/dist/lib/artifact.d.ts +10 -0
- package/dist/lib/artifact.d.ts.map +1 -0
- package/dist/lib/artifact.js +29 -0
- package/dist/lib/artifact.js.map +1 -0
- package/dist/lib/cf-tunnel.d.ts +11 -0
- package/dist/lib/cf-tunnel.d.ts.map +1 -0
- package/dist/lib/cf-tunnel.js +30 -0
- package/dist/lib/cf-tunnel.js.map +1 -0
- package/dist/lib/known-hosts.d.ts +3 -0
- package/dist/lib/known-hosts.d.ts.map +1 -0
- package/dist/lib/known-hosts.js +18 -0
- package/dist/lib/known-hosts.js.map +1 -0
- package/dist/lib/output.d.ts +14 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +56 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/run-log.d.ts +3 -0
- package/dist/lib/run-log.d.ts.map +1 -0
- package/dist/lib/run-log.js +62 -0
- package/dist/lib/run-log.js.map +1 -0
- package/dist/lib/templates.d.ts +2 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +6 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +3 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/logs/logs.command.d.ts +3 -0
- package/dist/logs/logs.command.d.ts.map +1 -0
- package/dist/logs/logs.command.js +86 -0
- package/dist/logs/logs.command.js.map +1 -0
- package/dist/monorepo/monorepo.command.d.ts +3 -0
- package/dist/monorepo/monorepo.command.d.ts.map +1 -0
- package/dist/monorepo/monorepo.command.js +28 -0
- package/dist/monorepo/monorepo.command.js.map +1 -0
- package/dist/pipelines/adopt-pipelines.d.ts +35 -0
- package/dist/pipelines/adopt-pipelines.d.ts.map +1 -0
- package/dist/pipelines/adopt-pipelines.js +77 -0
- package/dist/pipelines/adopt-pipelines.js.map +1 -0
- package/dist/pipelines/control-plane-sync.d.ts +24 -0
- package/dist/pipelines/control-plane-sync.d.ts.map +1 -0
- package/dist/pipelines/control-plane-sync.js +62 -0
- package/dist/pipelines/control-plane-sync.js.map +1 -0
- package/dist/plan/plan.command.d.ts +3 -0
- package/dist/plan/plan.command.d.ts.map +1 -0
- package/dist/plan/plan.command.js +33 -0
- package/dist/plan/plan.command.js.map +1 -0
- package/dist/resolve/resolve.command.d.ts +3 -0
- package/dist/resolve/resolve.command.d.ts.map +1 -0
- package/dist/resolve/resolve.command.js +78 -0
- package/dist/resolve/resolve.command.js.map +1 -0
- package/dist/resolve/resolve.d.ts +4 -0
- package/dist/resolve/resolve.d.ts.map +1 -0
- package/dist/resolve/resolve.js +33 -0
- package/dist/resolve/resolve.js.map +1 -0
- package/dist/restore/restore.command.d.ts +3 -0
- package/dist/restore/restore.command.d.ts.map +1 -0
- package/dist/restore/restore.command.js +68 -0
- package/dist/restore/restore.command.js.map +1 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.command.d.ts +3 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.command.d.ts.map +1 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.command.js +62 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.command.js.map +1 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.d.ts +18 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.d.ts.map +1 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.js +37 -0
- package/dist/sandbox-tunnel/sandbox-tunnel.js.map +1 -0
- package/dist/secrets/generated-secrets.d.ts +6 -0
- package/dist/secrets/generated-secrets.d.ts.map +1 -0
- package/dist/secrets/generated-secrets.js +26 -0
- package/dist/secrets/generated-secrets.js.map +1 -0
- package/dist/secrets/secret-store.d.ts +14 -0
- package/dist/secrets/secret-store.d.ts.map +1 -0
- package/dist/secrets/secret-store.js +111 -0
- package/dist/secrets/secret-store.js.map +1 -0
- package/dist/secrets/secrets.command.d.ts +6 -0
- package/dist/secrets/secrets.command.d.ts.map +1 -0
- package/dist/secrets/secrets.command.js +106 -0
- package/dist/secrets/secrets.command.js.map +1 -0
- package/dist/secrets/secrets.d.ts +7 -0
- package/dist/secrets/secrets.d.ts.map +1 -0
- package/dist/secrets/secrets.js +14 -0
- package/dist/secrets/secrets.js.map +1 -0
- package/package.json +69 -0
- package/templates/access.md.eta +21 -0
- package/templates/demo/Dockerfile.eta +5 -0
- package/templates/demo/deploy.config.ts.eta +23 -0
- package/templates/demo/env.eta +2 -0
- package/templates/env-example.eta +6 -0
- package/templates/scaffold/Dockerfile.eta +7 -0
- package/templates/scaffold/deploy.config.selfhost.ts.eta +18 -0
- package/templates/scaffold/deploy.config.ts.eta +22 -0
- package/templates/scaffold/server.js.eta +9 -0
- package/templates/workflows/apply.yaml.eta +28 -0
- package/templates/workflows/resolve.yaml.eta +26 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { secretRef } from "@intentic/graph";
|
|
2
|
+
import { forgejoApi } from "@intentic/providers";
|
|
3
|
+
import { ARTIFACT_FILE, CONFIG_FILE, INTENT_DIR, TARGET_DIR } from "../lib/artifact.js";
|
|
4
|
+
import { collectSecrets } from "../secrets/secrets.js";
|
|
5
|
+
import { APPLY_WORKFLOW_PATH, applyWorkflowYaml, setRepoSecrets, writeWorkflow } from "./adopt-pipelines.js";
|
|
6
|
+
export const forgejoIdentity = (graph) => {
|
|
7
|
+
const forgejo = Object.values(graph.resources).find((node) => node.type === "forgejo");
|
|
8
|
+
if (forgejo === undefined) {
|
|
9
|
+
throw new Error("no forgejo resource in the artifact — run `intentic apply` first");
|
|
10
|
+
}
|
|
11
|
+
const domain = forgejo.inputs["domain"];
|
|
12
|
+
const user = forgejo.inputs["adminUser"];
|
|
13
|
+
if (typeof domain !== "string" || typeof user !== "string") {
|
|
14
|
+
throw new Error("forgejo resource is missing its domain/adminUser inputs");
|
|
15
|
+
}
|
|
16
|
+
const adminPasswordRef = secretRef(forgejo.inputs["adminPassword"]);
|
|
17
|
+
if (adminPasswordRef === undefined) {
|
|
18
|
+
throw new Error("forgejo resource is missing its adminPassword secret");
|
|
19
|
+
}
|
|
20
|
+
return { domain, user, adminPasswordRef };
|
|
21
|
+
};
|
|
22
|
+
export const syncControlPlaneSecrets = async (args) => {
|
|
23
|
+
if (args.previousGraph === undefined) {
|
|
24
|
+
args.log("sync-control-plane: no previous artifact to diff against — skipping secret sync");
|
|
25
|
+
return { pushed: [], newEnv: [] };
|
|
26
|
+
}
|
|
27
|
+
const api = args.api ?? forgejoApi;
|
|
28
|
+
const { domain, user, adminPasswordRef } = forgejoIdentity(args.newGraph);
|
|
29
|
+
const previous = collectSecrets(args.previousGraph);
|
|
30
|
+
const next = collectSecrets(args.newGraph);
|
|
31
|
+
const addedGenerated = next.generated.filter((key) => !previous.generated.includes(key));
|
|
32
|
+
const newEnv = next.env.filter((key) => !previous.env.includes(key));
|
|
33
|
+
if (addedGenerated.length > 0) {
|
|
34
|
+
const secrets = {};
|
|
35
|
+
for (const key of addedGenerated) {
|
|
36
|
+
const value = args.env[key];
|
|
37
|
+
if (value === undefined || value === "") {
|
|
38
|
+
throw new Error(`generated secret ${key} has no value to push to Forgejo`);
|
|
39
|
+
}
|
|
40
|
+
secrets[key] = value;
|
|
41
|
+
}
|
|
42
|
+
await setRepoSecrets({ api, baseUrl: `https://${domain}`, user, password: args.password, owner: user, name: TARGET_DIR, secrets });
|
|
43
|
+
args.log(`sync-control-plane: pushed ${addedGenerated.length} new generated secret(s) to ${user}/${TARGET_DIR}: ${addedGenerated.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
const inputs = {
|
|
46
|
+
cliVersion: args.cliVersion,
|
|
47
|
+
user,
|
|
48
|
+
domain,
|
|
49
|
+
configFile: CONFIG_FILE,
|
|
50
|
+
artifactFile: ARTIFACT_FILE,
|
|
51
|
+
intentRepo: INTENT_DIR,
|
|
52
|
+
desiredStateRepo: TARGET_DIR,
|
|
53
|
+
applySecretKeys: [...next.generated, ...next.env].toSorted(),
|
|
54
|
+
forgejoPasswordKey: adminPasswordRef.key,
|
|
55
|
+
};
|
|
56
|
+
await writeWorkflow(args.dir, APPLY_WORKFLOW_PATH, applyWorkflowYaml(inputs));
|
|
57
|
+
if (newEnv.length > 0) {
|
|
58
|
+
args.log(`sync-control-plane: set these user secret(s) in the app's Secrets page (or \`intentic secrets push\` after setting .env) — apply fails until they reach ${user}/${TARGET_DIR}: ${newEnv.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
return { pushed: addedGenerated, newEnv };
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=control-plane-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-plane-sync.js","sourceRoot":"","sources":["../../src/pipelines/control-plane-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../src/plan/plan.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAUlE,eAAO,MAAM,WAAW,iDAqBtB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { plan } from "@intentic/engine";
|
|
3
|
+
import { createProviders, createSshExecutor } from "@intentic/providers";
|
|
4
|
+
import { buildCommand } from "@stricli/core";
|
|
5
|
+
import { loadConfig } from "../env.config.js";
|
|
6
|
+
import { ARTIFACT_PATH, loadEnvFile, readArtifact } from "../lib/artifact.js";
|
|
7
|
+
import { createKnownHostsStore } from "../lib/known-hosts.js";
|
|
8
|
+
import { createOutput } from "../lib/output.js";
|
|
9
|
+
import { withRunLog } from "../lib/run-log.js";
|
|
10
|
+
import { ensureGeneratedSecrets } from "../secrets/generated-secrets.js";
|
|
11
|
+
import { generatedSecretStore } from "../secrets/secret-store.js";
|
|
12
|
+
import { collectSecrets } from "../secrets/secrets.js";
|
|
13
|
+
export const planCommand = buildCommand({
|
|
14
|
+
docs: { brief: "Show what applying the artifact would create/update (read-only)" },
|
|
15
|
+
parameters: {
|
|
16
|
+
flags: { artifact: { kind: "parsed", parse: String, optional: true, brief: `Path to the artifact (default: ${ARTIFACT_PATH})` } },
|
|
17
|
+
},
|
|
18
|
+
async func(flags) {
|
|
19
|
+
const out = createOutput(withRunLog(this.process.stdout, "plan"), loadConfig().intenticOutput);
|
|
20
|
+
const artifact = flags.artifact ?? ARTIFACT_PATH;
|
|
21
|
+
const dir = dirname(artifact);
|
|
22
|
+
loadEnvFile(dir);
|
|
23
|
+
const graph = await readArtifact(artifact);
|
|
24
|
+
const ssh = createSshExecutor(createKnownHostsStore(dir));
|
|
25
|
+
await ensureGeneratedSecrets(generatedSecretStore(graph, dir, ssh, false, out.log), collectSecrets(graph).generated, process.env);
|
|
26
|
+
const outcome = await plan(graph, { providers: createProviders({ ssh }), log: out.log, onEvent: out.onEvent });
|
|
27
|
+
for (const step of outcome.steps) {
|
|
28
|
+
out.text(`${step.action}\t${step.type}\t${step.id}${step.reason !== undefined ? `\t(${step.reason})` : ""}`);
|
|
29
|
+
}
|
|
30
|
+
out.result({ steps: outcome.steps, orphans: outcome.orphans });
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=plan.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.command.js","sourceRoot":"","sources":["../../src/plan/plan.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAuB,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAwB;IAC3D,IAAI,EAAE,EAAE,KAAK,EAAE,iEAAiE,EAAE;IAClF,UAAU,EAAE;QACR,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,kCAAkC,aAAa,GAAG,EAAE,EAAE;KACpI;IACD,KAAK,CAAC,IAAI,CAAuB,KAA4B;QACzD,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,cAAc,CAAC,CAAC;QAC/F,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,aAAa,CAAC;QACjD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9B,WAAW,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,iBAAiB,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;QAG1D,MAAM,sBAAsB,CAAC,oBAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAClI,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/G,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjH,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.command.d.ts","sourceRoot":"","sources":["../../src/resolve/resolve.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAmBlE,eAAO,MAAM,cAAc,iDAoEzB,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { resolveState } from "@intentic/state-resolver";
|
|
4
|
+
import { buildCommand } from "@stricli/core";
|
|
5
|
+
import { loadConfig } from "../env.config.js";
|
|
6
|
+
import { ARTIFACT_PATH, CONFIG_PATH, ENV_FILE, readArtifact, writeArtifact } from "../lib/artifact.js";
|
|
7
|
+
import { createOutput } from "../lib/output.js";
|
|
8
|
+
import { withRunLog } from "../lib/run-log.js";
|
|
9
|
+
import { version } from "../lib/version.js";
|
|
10
|
+
import { GIT_TOKEN_ENV } from "../pipelines/adopt-pipelines.js";
|
|
11
|
+
import { syncControlPlaneSecrets } from "../pipelines/control-plane-sync.js";
|
|
12
|
+
import { ensureGeneratedSecrets } from "../secrets/generated-secrets.js";
|
|
13
|
+
import { createLocalSecretStore } from "../secrets/secret-store.js";
|
|
14
|
+
import { collectSecrets, writeEnvExample } from "../secrets/secrets.js";
|
|
15
|
+
import { discoverZone, loadIntent } from "./resolve.js";
|
|
16
|
+
export const resolveCommand = buildCommand({
|
|
17
|
+
docs: { brief: "Resolve a deploy.config.ts into the desired-state artifact" },
|
|
18
|
+
parameters: {
|
|
19
|
+
flags: {
|
|
20
|
+
config: { kind: "parsed", parse: String, optional: true, brief: `Path to the intent config (default: ${CONFIG_PATH})` },
|
|
21
|
+
out: { kind: "parsed", parse: String, optional: true, brief: `Path to write the artifact (default: ${ARTIFACT_PATH})` },
|
|
22
|
+
syncControlPlane: {
|
|
23
|
+
kind: "boolean",
|
|
24
|
+
brief: "Push newly-required generated secrets into Forgejo and regenerate apply.yaml (run by the resolve pipeline post-adopt; needs GIT_TOKEN)",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
async func(flags) {
|
|
29
|
+
const out = createOutput(withRunLog(this.process.stdout, "resolve"), loadConfig().intenticOutput);
|
|
30
|
+
const intent = await loadIntent(flags.config ?? CONFIG_PATH);
|
|
31
|
+
const artifactOut = flags.out ?? ARTIFACT_PATH;
|
|
32
|
+
const dir = dirname(artifactOut);
|
|
33
|
+
const previousGraph = flags.syncControlPlane && existsSync(artifactOut) ? await readArtifact(artifactOut) : undefined;
|
|
34
|
+
const zone = await discoverZone(intent, dir);
|
|
35
|
+
const graph = resolveState(intent, zone);
|
|
36
|
+
await writeArtifact(artifactOut, graph);
|
|
37
|
+
const count = Object.keys(graph.resources).length;
|
|
38
|
+
out.text(`resolved desired state (${count} resources) → ${artifactOut}`);
|
|
39
|
+
if (zone !== undefined) {
|
|
40
|
+
out.text(intent.cloudflare?.input.zone !== undefined
|
|
41
|
+
? `using Cloudflare zone "${zone}" from the intent`
|
|
42
|
+
: `discovered Cloudflare zone "${zone}" from the API token`);
|
|
43
|
+
}
|
|
44
|
+
const { env: envKeys, generated } = collectSecrets(graph);
|
|
45
|
+
if (envKeys.length > 0) {
|
|
46
|
+
await writeEnvExample(join(dir, `${ENV_FILE}.example`), envKeys);
|
|
47
|
+
out.text(`set these in ${ENV_FILE} before apply (see ${ENV_FILE}.example): ${envKeys.join(", ")}`);
|
|
48
|
+
}
|
|
49
|
+
if (generated.length > 0) {
|
|
50
|
+
await ensureGeneratedSecrets(createLocalSecretStore(dir), generated, process.env);
|
|
51
|
+
out.text(`generated these (stored in .secrets.json): ${generated.join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
let synced;
|
|
54
|
+
if (flags.syncControlPlane) {
|
|
55
|
+
const password = process.env[GIT_TOKEN_ENV];
|
|
56
|
+
if (password === undefined || password === "") {
|
|
57
|
+
throw new Error(`set ${GIT_TOKEN_ENV} (the Forgejo admin password) to use --sync-control-plane`);
|
|
58
|
+
}
|
|
59
|
+
synced = await syncControlPlaneSecrets({
|
|
60
|
+
previousGraph,
|
|
61
|
+
newGraph: graph,
|
|
62
|
+
env: process.env,
|
|
63
|
+
dir,
|
|
64
|
+
password,
|
|
65
|
+
cliVersion: version,
|
|
66
|
+
log: out.log,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
out.result({
|
|
70
|
+
resources: count,
|
|
71
|
+
...(zone !== undefined ? { zone } : {}),
|
|
72
|
+
envSecrets: envKeys,
|
|
73
|
+
generatedSecrets: generated,
|
|
74
|
+
...(synced !== undefined ? { synced } : {}),
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=resolve.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.command.js","sourceRoot":"","sources":["../../src/resolve/resolve.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IntentSet } from "@intentic/need-resolver";
|
|
2
|
+
export declare const loadIntent: (configPath: string) => Promise<IntentSet>;
|
|
3
|
+
export declare const discoverZone: (intent: IntentSet, dir: string) => Promise<string | undefined>;
|
|
4
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/resolve/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAQzD,eAAO,MAAM,UAAU,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,SAAS,CAMtE,CAAC;AAQF,eAAO,MAAM,YAAY,GAAU,QAAQ,SAAS,EAAE,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAsB7F,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { cloudflareApi } from "@intentic/providers";
|
|
4
|
+
import { collectDomains, selectZone } from "@intentic/state-resolver";
|
|
5
|
+
import { loadEnvFile } from "../lib/artifact.js";
|
|
6
|
+
export const loadIntent = async (configPath) => {
|
|
7
|
+
const loaded = (await import(pathToFileURL(resolve(configPath)).href));
|
|
8
|
+
if (loaded.intent === undefined) {
|
|
9
|
+
throw new Error(`${configPath} must export "intent" (from defineIntent)`);
|
|
10
|
+
}
|
|
11
|
+
return loaded.intent;
|
|
12
|
+
};
|
|
13
|
+
export const discoverZone = async (intent, dir) => {
|
|
14
|
+
const cloudflare = intent.cloudflare;
|
|
15
|
+
if (cloudflare === undefined || (intent.apps.length === 0 && intent.services.length === 0)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
if (cloudflare.input.zone !== undefined) {
|
|
19
|
+
return selectZone([cloudflare.input.zone], collectDomains(intent));
|
|
20
|
+
}
|
|
21
|
+
loadEnvFile(dir);
|
|
22
|
+
const token = cloudflare.input.apiToken;
|
|
23
|
+
if (token.source !== "env") {
|
|
24
|
+
throw new Error(`cloudflare apiToken must be an env() secret, but it is "${token.source}"`);
|
|
25
|
+
}
|
|
26
|
+
const apiToken = process.env[token.key];
|
|
27
|
+
if (apiToken === undefined || apiToken === "") {
|
|
28
|
+
throw new Error(`set ${token.key} (your Cloudflare API token) before resolve — it is needed to discover your zone and account`);
|
|
29
|
+
}
|
|
30
|
+
const zones = await cloudflareApi.listZones({ apiToken });
|
|
31
|
+
return selectZone(zones.map((zone) => zone.name), collectDomains(intent));
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/resolve/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKjD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,UAAkB,EAAsB,EAAE;IACvE,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAA2B,CAAC;IACjG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,2CAA2C,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACzB,CAAC,CAAC;AAQF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,MAAiB,EAAE,GAAW,EAA+B,EAAE;IAC9F,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACzF,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,UAAU,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,WAAW,CAAC,GAAG,CAAC,CAAC;IACjB,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2DAA2D,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,GAAG,8FAA8F,CAAC,CAAC;IACpI,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1D,OAAO,UAAU,CACb,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAC9B,cAAc,CAAC,MAAM,CAAC,CACzB,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.command.d.ts","sourceRoot":"","sources":["../../src/restore/restore.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAgBlE,eAAO,MAAM,OAAO,iDA0DlB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { createStore, resolveInputs } from "@intentic/engine";
|
|
3
|
+
import { createSshExecutor, hostTarget, restoreBackup } from "@intentic/providers";
|
|
4
|
+
import { buildCommand } from "@stricli/core";
|
|
5
|
+
import { loadConfig } from "../env.config.js";
|
|
6
|
+
import { ARTIFACT_PATH, loadEnvFile, readArtifact } from "../lib/artifact.js";
|
|
7
|
+
import { createKnownHostsStore } from "../lib/known-hosts.js";
|
|
8
|
+
import { createOutput } from "../lib/output.js";
|
|
9
|
+
import { withRunLog } from "../lib/run-log.js";
|
|
10
|
+
import { ensureGeneratedSecrets } from "../secrets/generated-secrets.js";
|
|
11
|
+
import { generatedSecretStore } from "../secrets/secret-store.js";
|
|
12
|
+
import { collectSecrets } from "../secrets/secrets.js";
|
|
13
|
+
export const restore = buildCommand({
|
|
14
|
+
docs: { brief: "Restore Forgejo/Komodo from a restic backup snapshot, then re-apply (one-shot recovery)" },
|
|
15
|
+
parameters: {
|
|
16
|
+
flags: {
|
|
17
|
+
artifact: { kind: "parsed", parse: String, optional: true, brief: `Path to the artifact (default: ${ARTIFACT_PATH})` },
|
|
18
|
+
snapshot: { kind: "parsed", parse: String, optional: true, brief: "restic snapshot id to restore (default: latest)" },
|
|
19
|
+
only: { kind: "parsed", parse: String, optional: true, brief: "Which to restore: forgejo | komodo | all (default: all)" },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async func(flags) {
|
|
23
|
+
const out = createOutput(withRunLog(this.process.stdout, "restore"), loadConfig().intenticOutput);
|
|
24
|
+
const artifact = flags.artifact ?? ARTIFACT_PATH;
|
|
25
|
+
const dir = dirname(artifact);
|
|
26
|
+
loadEnvFile(dir);
|
|
27
|
+
const graph = await readArtifact(artifact);
|
|
28
|
+
const ssh = createSshExecutor(createKnownHostsStore(dir));
|
|
29
|
+
await ensureGeneratedSecrets(generatedSecretStore(graph, dir, ssh, false, out.log), collectSecrets(graph).generated, process.env);
|
|
30
|
+
const backupNode = Object.values(graph.resources).find((node) => node.type === "backup");
|
|
31
|
+
if (backupNode === undefined) {
|
|
32
|
+
throw new Error("no backup resource in the artifact — declare one with i.have.backup and apply it first");
|
|
33
|
+
}
|
|
34
|
+
const scope = flags.only ?? "all";
|
|
35
|
+
if (scope !== "forgejo" && scope !== "komodo" && scope !== "all") {
|
|
36
|
+
throw new Error(`--only must be one of forgejo|komodo|all, got "${scope}"`);
|
|
37
|
+
}
|
|
38
|
+
const resolved = resolveInputs(backupNode.inputs, createStore(), process.env, { lenient: false });
|
|
39
|
+
const repo = resolved["repo"];
|
|
40
|
+
const password = resolved["password"];
|
|
41
|
+
const image = resolved["image"];
|
|
42
|
+
if (typeof repo !== "string" || typeof password !== "string" || typeof image !== "string") {
|
|
43
|
+
throw new Error("backup resource is missing its repo/password/image inputs");
|
|
44
|
+
}
|
|
45
|
+
const credsRaw = resolved["credentials"];
|
|
46
|
+
const credentials = {};
|
|
47
|
+
if (typeof credsRaw === "object" && credsRaw !== null) {
|
|
48
|
+
for (const [key, value] of Object.entries(credsRaw)) {
|
|
49
|
+
if (typeof value === "string") {
|
|
50
|
+
credentials[key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
await restoreBackup({
|
|
55
|
+
target: hostTarget(resolved),
|
|
56
|
+
image,
|
|
57
|
+
repo,
|
|
58
|
+
password,
|
|
59
|
+
credentials,
|
|
60
|
+
snapshot: flags.snapshot ?? "latest",
|
|
61
|
+
scope: scope,
|
|
62
|
+
log: out.log,
|
|
63
|
+
executor: ssh,
|
|
64
|
+
});
|
|
65
|
+
out.result({ snapshot: flags.snapshot ?? "latest", scope });
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=restore.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.command.js","sourceRoot":"","sources":["../../src/restore/restore.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-tunnel.command.d.ts","sourceRoot":"","sources":["../../src/sandbox-tunnel/sandbox-tunnel.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAQlE,eAAO,MAAM,aAAa,iDA4DxB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { buildCommand } from "@stricli/core";
|
|
2
|
+
import { loadConfig } from "../env.config.js";
|
|
3
|
+
import { createSandboxTunnel } from "./sandbox-tunnel.js";
|
|
4
|
+
export const sandboxTunnel = buildCommand({
|
|
5
|
+
docs: { brief: "Create/refresh the per-sandbox Cloudflare tunnel + DNS and print its connector token (used by connect.sh)" },
|
|
6
|
+
parameters: {
|
|
7
|
+
flags: {
|
|
8
|
+
service: {
|
|
9
|
+
kind: "parsed",
|
|
10
|
+
parse: String,
|
|
11
|
+
brief: "Internal service URL the tunnel routes to (e.g. http://intentic-sandbox-workspace:8787)",
|
|
12
|
+
},
|
|
13
|
+
previewService: {
|
|
14
|
+
kind: "parsed",
|
|
15
|
+
parse: String,
|
|
16
|
+
optional: true,
|
|
17
|
+
brief: "Preview-proxy URL to route the *.<zone> wildcard to (e.g. http://intentic-sandbox-workspace:5173)",
|
|
18
|
+
},
|
|
19
|
+
sshService: {
|
|
20
|
+
kind: "parsed",
|
|
21
|
+
parse: String,
|
|
22
|
+
optional: true,
|
|
23
|
+
brief: "SSH URL to route ssh-<id>.<zone> to for local sync (e.g. ssh://intentic-sandbox-workspace:22)",
|
|
24
|
+
},
|
|
25
|
+
zone: {
|
|
26
|
+
kind: "parsed",
|
|
27
|
+
parse: String,
|
|
28
|
+
optional: true,
|
|
29
|
+
brief: "Cloudflare zone for the DNS record (default: the API token's sole zone, or set ZONE)",
|
|
30
|
+
},
|
|
31
|
+
subdomain: {
|
|
32
|
+
kind: "parsed",
|
|
33
|
+
parse: String,
|
|
34
|
+
optional: true,
|
|
35
|
+
brief: "Explicit subdomain prefix for the hostname (default: the derived sandbox-<id>)",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
async func(flags) {
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
const { cloudflareApiToken: apiToken, connectToken } = config;
|
|
42
|
+
if (apiToken === "") {
|
|
43
|
+
throw new Error("set CLOUDFLARE_API_TOKEN");
|
|
44
|
+
}
|
|
45
|
+
if (connectToken === "") {
|
|
46
|
+
throw new Error("set CONNECT_TOKEN (the per-sandbox connection token)");
|
|
47
|
+
}
|
|
48
|
+
const zone = flags.zone ?? (config.zone !== "" ? config.zone : undefined);
|
|
49
|
+
const { token, hostname, sshHostname } = await createSandboxTunnel({
|
|
50
|
+
apiToken,
|
|
51
|
+
connectToken,
|
|
52
|
+
service: flags.service,
|
|
53
|
+
...(flags.previewService !== undefined && flags.previewService !== "" ? { previewService: flags.previewService } : {}),
|
|
54
|
+
...(flags.sshService !== undefined && flags.sshService !== "" ? { sshService: flags.sshService } : {}),
|
|
55
|
+
...(zone !== undefined && zone !== "" ? { zone } : {}),
|
|
56
|
+
...(flags.subdomain !== undefined && flags.subdomain !== "" ? { subdomain: flags.subdomain } : {}),
|
|
57
|
+
log: (message) => this.process.stderr.write(`${message}\n`),
|
|
58
|
+
});
|
|
59
|
+
this.process.stdout.write(`TUNNEL_TOKEN=${token}\nSANDBOX_HOSTNAME=${hostname}\n${sshHostname !== undefined ? `SANDBOX_SSH_HOSTNAME=${sshHostname}\n` : ""}`);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=sandbox-tunnel.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-tunnel.command.js","sourceRoot":"","sources":["../../src/sandbox-tunnel/sandbox-tunnel.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CloudflareApi } from "@intentic/providers";
|
|
2
|
+
export interface SandboxTunnelResult {
|
|
3
|
+
readonly token: string;
|
|
4
|
+
readonly hostname: string;
|
|
5
|
+
readonly sshHostname: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare const createSandboxTunnel: (args: {
|
|
8
|
+
readonly apiToken: string;
|
|
9
|
+
readonly connectToken: string;
|
|
10
|
+
readonly service: string;
|
|
11
|
+
readonly previewService?: string;
|
|
12
|
+
readonly sshService?: string;
|
|
13
|
+
readonly zone?: string;
|
|
14
|
+
readonly subdomain?: string;
|
|
15
|
+
readonly log: (message: string) => void;
|
|
16
|
+
readonly api?: CloudflareApi;
|
|
17
|
+
}) => Promise<SandboxTunnelResult>;
|
|
18
|
+
//# sourceMappingURL=sandbox-tunnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-tunnel.d.ts","sourceRoot":"","sources":["../../src/sandbox-tunnel/sandbox-tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAIxE,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAG1B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAMD,eAAO,MAAM,mBAAmB,GAAU,MAAM;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAGjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC;CAChC,KAAG,OAAO,CAAC,mBAAmB,CAkC9B,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { cloudflareApi } from "@intentic/providers";
|
|
2
|
+
import { sandboxIdFromToken } from "@intentic/sandbox-contract/tunnel-ids";
|
|
3
|
+
import { CATCH_ALL, resolveZone, upsertCname } from "../lib/cf-tunnel.js";
|
|
4
|
+
export const createSandboxTunnel = async (args) => {
|
|
5
|
+
const { apiToken, connectToken, service, previewService, sshService, log } = args;
|
|
6
|
+
const api = args.api ?? cloudflareApi;
|
|
7
|
+
const zone = await resolveZone(api, apiToken, args.zone);
|
|
8
|
+
const id = sandboxIdFromToken(connectToken) ?? "";
|
|
9
|
+
const name = args.subdomain !== undefined && args.subdomain !== "" ? args.subdomain : `sandbox-${id}`;
|
|
10
|
+
const hostname = `${name}.${zone.name}`;
|
|
11
|
+
const previewHostname = `*.${zone.name}`;
|
|
12
|
+
const sshHostname = `ssh-${id}.${zone.name}`;
|
|
13
|
+
const withPreview = previewService !== undefined && previewService !== "";
|
|
14
|
+
const withSsh = sshService !== undefined && sshService !== "";
|
|
15
|
+
log(`resolving tunnel "${name}" on zone "${zone.name}"…`);
|
|
16
|
+
const existing = await api.findTunnel({ accountId: zone.accountId, apiToken, name });
|
|
17
|
+
const tunnel = existing ?? (await api.createTunnel({ accountId: zone.accountId, apiToken, name }));
|
|
18
|
+
const token = await api.getTunnelToken({ accountId: zone.accountId, apiToken, tunnelId: tunnel.id });
|
|
19
|
+
const ingress = [
|
|
20
|
+
{ hostname, service },
|
|
21
|
+
...(withSsh ? [{ hostname: sshHostname, service: sshService }] : []),
|
|
22
|
+
...(withPreview ? [{ hostname: previewHostname, service: previewService }] : []),
|
|
23
|
+
CATCH_ALL,
|
|
24
|
+
];
|
|
25
|
+
await api.putTunnelIngress({ accountId: zone.accountId, apiToken, tunnelId: tunnel.id, ingress });
|
|
26
|
+
const cname = `${tunnel.id}.cfargotunnel.com`;
|
|
27
|
+
await upsertCname(api, apiToken, zone.id, hostname, cname, "intentic sandbox tunnel");
|
|
28
|
+
if (withPreview) {
|
|
29
|
+
await upsertCname(api, apiToken, zone.id, previewHostname, cname, "intentic sandbox tunnel");
|
|
30
|
+
}
|
|
31
|
+
if (withSsh) {
|
|
32
|
+
await upsertCname(api, apiToken, zone.id, sshHostname, cname, "intentic sandbox ssh tunnel");
|
|
33
|
+
}
|
|
34
|
+
log(`tunnel "${name}" → ${hostname} ready`);
|
|
35
|
+
return { token, hostname, sshHostname: withSsh ? sshHostname : undefined };
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=sandbox-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-tunnel.js","sourceRoot":"","sources":["../../src/sandbox-tunnel/sandbox-tunnel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SecretStore } from "./secret-store.js";
|
|
2
|
+
type MutableEnv = Record<string, string | undefined>;
|
|
3
|
+
export declare const ensureGeneratedSecrets: (store: SecretStore, keys: readonly string[], env: MutableEnv) => Promise<void>;
|
|
4
|
+
export declare const readGeneratedSecrets: (dir: string) => Promise<Record<string, string>>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=generated-secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-secrets.d.ts","sourceRoot":"","sources":["../../src/secrets/generated-secrets.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAcrD,eAAO,MAAM,sBAAsB,GAAU,OAAO,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,EAAE,KAAK,UAAU,KAAG,OAAO,CAAC,IAAI,CAcvH,CAAC;AAKF,eAAO,MAAM,oBAAoB,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGtF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { SECRETS_FILE } from "../lib/artifact.js";
|
|
6
|
+
const generate = () => randomBytes(16).toString("hex");
|
|
7
|
+
export const ensureGeneratedSecrets = async (store, keys, env) => {
|
|
8
|
+
for (const key of keys) {
|
|
9
|
+
if (env[key] !== undefined && env[key] !== "") {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const existing = await store.get(key);
|
|
13
|
+
if (existing !== undefined) {
|
|
14
|
+
env[key] = existing;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const value = generate();
|
|
18
|
+
await store.set(key, value);
|
|
19
|
+
env[key] = value;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const readGeneratedSecrets = async (dir) => {
|
|
23
|
+
const path = join(dir, SECRETS_FILE);
|
|
24
|
+
return existsSync(path) ? JSON.parse(await readFile(path, "utf8")) : {};
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=generated-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-secrets.js","sourceRoot":"","sources":["../../src/secrets/generated-secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAU/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EAAE,KAAkB,EAAE,IAAuB,EAAE,GAAe,EAAiB,EAAE;IACxH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;YAC5C,SAAS;QACb,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzB,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;YACpB,SAAS;QACb,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrB,CAAC;AACL,CAAC,CAAC;AAKF,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,GAAW,EAAmC,EAAE;IACvF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACrC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC,CAAC,CAAC,EAAE,CAAC;AACxG,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DesiredStateGraph } from "@intentic/graph";
|
|
2
|
+
import { type SshExecutor, type SshTarget } from "@intentic/providers";
|
|
3
|
+
export interface SecretStore {
|
|
4
|
+
readonly get: (key: string) => Promise<string | undefined>;
|
|
5
|
+
readonly set: (key: string, value: string) => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const createLocalSecretStore: (dir: string) => SecretStore;
|
|
8
|
+
export declare const createHostSecretStore: (target: SshTarget, executor: SshExecutor) => SecretStore;
|
|
9
|
+
export declare const createLayeredSecretStore: (layers: readonly SecretStore[], options: {
|
|
10
|
+
readonly backfill: boolean;
|
|
11
|
+
readonly log?: (message: string) => void;
|
|
12
|
+
}) => SecretStore;
|
|
13
|
+
export declare const generatedSecretStore: (graph: DesiredStateGraph, dir: string, ssh: SshExecutor, backfill: boolean, log: (message: string) => void) => SecretStore;
|
|
14
|
+
//# sourceMappingURL=secret-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-store.d.ts","sourceRoot":"","sources":["../../src/secrets/secret-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAc,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAOnF,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAID,eAAO,MAAM,sBAAsB,GAAI,KAAK,MAAM,KAAG,WAYpD,CAAC;AAOF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,EAAE,UAAU,WAAW,KAAG,WAiChF,CAAC;AAOF,eAAO,MAAM,wBAAwB,GACjC,QAAQ,SAAS,WAAW,EAAE,EAC9B,SAAS;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,KAClF,WA2CF,CAAC;AAUF,eAAO,MAAM,oBAAoB,GAC7B,OAAO,iBAAiB,EACxB,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,UAAU,OAAO,EACjB,KAAK,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,KAC/B,WAYF,CAAC"}
|