@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.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/dist/add-app/add-app.command.d.ts +3 -0
  4. package/dist/add-app/add-app.command.d.ts.map +1 -0
  5. package/dist/add-app/add-app.command.js +50 -0
  6. package/dist/add-app/add-app.command.js.map +1 -0
  7. package/dist/adopt/adopt.command.d.ts +3 -0
  8. package/dist/adopt/adopt.command.d.ts.map +1 -0
  9. package/dist/adopt/adopt.command.js +77 -0
  10. package/dist/adopt/adopt.command.js.map +1 -0
  11. package/dist/adopt/adopt.d.ts +21 -0
  12. package/dist/adopt/adopt.d.ts.map +1 -0
  13. package/dist/adopt/adopt.js +31 -0
  14. package/dist/adopt/adopt.js.map +1 -0
  15. package/dist/app.d.ts +2 -0
  16. package/dist/app.d.ts.map +1 -0
  17. package/dist/app.js +46 -0
  18. package/dist/app.js.map +1 -0
  19. package/dist/apply/access.d.ts +16 -0
  20. package/dist/apply/access.d.ts.map +1 -0
  21. package/dist/apply/access.js +72 -0
  22. package/dist/apply/access.js.map +1 -0
  23. package/dist/apply/apply-lock.d.ts +12 -0
  24. package/dist/apply/apply-lock.d.ts.map +1 -0
  25. package/dist/apply/apply-lock.js +102 -0
  26. package/dist/apply/apply-lock.js.map +1 -0
  27. package/dist/apply/apply.command.d.ts +3 -0
  28. package/dist/apply/apply.command.d.ts.map +1 -0
  29. package/dist/apply/apply.command.js +144 -0
  30. package/dist/apply/apply.command.js.map +1 -0
  31. package/dist/apply/migrate.d.ts +20 -0
  32. package/dist/apply/migrate.d.ts.map +1 -0
  33. package/dist/apply/migrate.js +112 -0
  34. package/dist/apply/migrate.js.map +1 -0
  35. package/dist/cli.d.ts +3 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +5 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/demo.d.ts +2 -0
  40. package/dist/demo.d.ts.map +1 -0
  41. package/dist/demo.js +281 -0
  42. package/dist/demo.js.map +1 -0
  43. package/dist/deployments/deployments.command.d.ts +3 -0
  44. package/dist/deployments/deployments.command.d.ts.map +1 -0
  45. package/dist/deployments/deployments.command.js +19 -0
  46. package/dist/deployments/deployments.command.js.map +1 -0
  47. package/dist/deployments/deployments.d.ts +14 -0
  48. package/dist/deployments/deployments.d.ts.map +1 -0
  49. package/dist/deployments/deployments.js +83 -0
  50. package/dist/deployments/deployments.js.map +1 -0
  51. package/dist/env.config.d.ts +25 -0
  52. package/dist/env.config.d.ts.map +1 -0
  53. package/dist/env.config.js +31 -0
  54. package/dist/env.config.js.map +1 -0
  55. package/dist/host-ssh-tunnel/host-ssh-tunnel.command.d.ts +3 -0
  56. package/dist/host-ssh-tunnel/host-ssh-tunnel.command.d.ts.map +1 -0
  57. package/dist/host-ssh-tunnel/host-ssh-tunnel.command.js +39 -0
  58. package/dist/host-ssh-tunnel/host-ssh-tunnel.command.js.map +1 -0
  59. package/dist/host-ssh-tunnel/host-ssh-tunnel.d.ts +14 -0
  60. package/dist/host-ssh-tunnel/host-ssh-tunnel.d.ts.map +1 -0
  61. package/dist/host-ssh-tunnel/host-ssh-tunnel.js +21 -0
  62. package/dist/host-ssh-tunnel/host-ssh-tunnel.js.map +1 -0
  63. package/dist/index.d.ts +5 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +5 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/init/init.command.d.ts +3 -0
  68. package/dist/init/init.command.d.ts.map +1 -0
  69. package/dist/init/init.command.js +45 -0
  70. package/dist/init/init.command.js.map +1 -0
  71. package/dist/init/init.d.ts +7 -0
  72. package/dist/init/init.d.ts.map +1 -0
  73. package/dist/init/init.js +39 -0
  74. package/dist/init/init.js.map +1 -0
  75. package/dist/init/scaffold-app.d.ts +2 -0
  76. package/dist/init/scaffold-app.d.ts.map +1 -0
  77. package/dist/init/scaffold-app.js +27 -0
  78. package/dist/init/scaffold-app.js.map +1 -0
  79. package/dist/lib/artifact.d.ts +10 -0
  80. package/dist/lib/artifact.d.ts.map +1 -0
  81. package/dist/lib/artifact.js +29 -0
  82. package/dist/lib/artifact.js.map +1 -0
  83. package/dist/lib/cf-tunnel.d.ts +11 -0
  84. package/dist/lib/cf-tunnel.d.ts.map +1 -0
  85. package/dist/lib/cf-tunnel.js +30 -0
  86. package/dist/lib/cf-tunnel.js.map +1 -0
  87. package/dist/lib/known-hosts.d.ts +3 -0
  88. package/dist/lib/known-hosts.d.ts.map +1 -0
  89. package/dist/lib/known-hosts.js +18 -0
  90. package/dist/lib/known-hosts.js.map +1 -0
  91. package/dist/lib/output.d.ts +14 -0
  92. package/dist/lib/output.d.ts.map +1 -0
  93. package/dist/lib/output.js +56 -0
  94. package/dist/lib/output.js.map +1 -0
  95. package/dist/lib/run-log.d.ts +3 -0
  96. package/dist/lib/run-log.d.ts.map +1 -0
  97. package/dist/lib/run-log.js +62 -0
  98. package/dist/lib/run-log.js.map +1 -0
  99. package/dist/lib/templates.d.ts +2 -0
  100. package/dist/lib/templates.d.ts.map +1 -0
  101. package/dist/lib/templates.js +6 -0
  102. package/dist/lib/templates.js.map +1 -0
  103. package/dist/lib/version.d.ts +2 -0
  104. package/dist/lib/version.d.ts.map +1 -0
  105. package/dist/lib/version.js +3 -0
  106. package/dist/lib/version.js.map +1 -0
  107. package/dist/logs/logs.command.d.ts +3 -0
  108. package/dist/logs/logs.command.d.ts.map +1 -0
  109. package/dist/logs/logs.command.js +86 -0
  110. package/dist/logs/logs.command.js.map +1 -0
  111. package/dist/monorepo/monorepo.command.d.ts +3 -0
  112. package/dist/monorepo/monorepo.command.d.ts.map +1 -0
  113. package/dist/monorepo/monorepo.command.js +28 -0
  114. package/dist/monorepo/monorepo.command.js.map +1 -0
  115. package/dist/pipelines/adopt-pipelines.d.ts +35 -0
  116. package/dist/pipelines/adopt-pipelines.d.ts.map +1 -0
  117. package/dist/pipelines/adopt-pipelines.js +77 -0
  118. package/dist/pipelines/adopt-pipelines.js.map +1 -0
  119. package/dist/pipelines/control-plane-sync.d.ts +24 -0
  120. package/dist/pipelines/control-plane-sync.d.ts.map +1 -0
  121. package/dist/pipelines/control-plane-sync.js +62 -0
  122. package/dist/pipelines/control-plane-sync.js.map +1 -0
  123. package/dist/plan/plan.command.d.ts +3 -0
  124. package/dist/plan/plan.command.d.ts.map +1 -0
  125. package/dist/plan/plan.command.js +33 -0
  126. package/dist/plan/plan.command.js.map +1 -0
  127. package/dist/resolve/resolve.command.d.ts +3 -0
  128. package/dist/resolve/resolve.command.d.ts.map +1 -0
  129. package/dist/resolve/resolve.command.js +78 -0
  130. package/dist/resolve/resolve.command.js.map +1 -0
  131. package/dist/resolve/resolve.d.ts +4 -0
  132. package/dist/resolve/resolve.d.ts.map +1 -0
  133. package/dist/resolve/resolve.js +33 -0
  134. package/dist/resolve/resolve.js.map +1 -0
  135. package/dist/restore/restore.command.d.ts +3 -0
  136. package/dist/restore/restore.command.d.ts.map +1 -0
  137. package/dist/restore/restore.command.js +68 -0
  138. package/dist/restore/restore.command.js.map +1 -0
  139. package/dist/sandbox-tunnel/sandbox-tunnel.command.d.ts +3 -0
  140. package/dist/sandbox-tunnel/sandbox-tunnel.command.d.ts.map +1 -0
  141. package/dist/sandbox-tunnel/sandbox-tunnel.command.js +62 -0
  142. package/dist/sandbox-tunnel/sandbox-tunnel.command.js.map +1 -0
  143. package/dist/sandbox-tunnel/sandbox-tunnel.d.ts +18 -0
  144. package/dist/sandbox-tunnel/sandbox-tunnel.d.ts.map +1 -0
  145. package/dist/sandbox-tunnel/sandbox-tunnel.js +37 -0
  146. package/dist/sandbox-tunnel/sandbox-tunnel.js.map +1 -0
  147. package/dist/secrets/generated-secrets.d.ts +6 -0
  148. package/dist/secrets/generated-secrets.d.ts.map +1 -0
  149. package/dist/secrets/generated-secrets.js +26 -0
  150. package/dist/secrets/generated-secrets.js.map +1 -0
  151. package/dist/secrets/secret-store.d.ts +14 -0
  152. package/dist/secrets/secret-store.d.ts.map +1 -0
  153. package/dist/secrets/secret-store.js +111 -0
  154. package/dist/secrets/secret-store.js.map +1 -0
  155. package/dist/secrets/secrets.command.d.ts +6 -0
  156. package/dist/secrets/secrets.command.d.ts.map +1 -0
  157. package/dist/secrets/secrets.command.js +106 -0
  158. package/dist/secrets/secrets.command.js.map +1 -0
  159. package/dist/secrets/secrets.d.ts +7 -0
  160. package/dist/secrets/secrets.d.ts.map +1 -0
  161. package/dist/secrets/secrets.js +14 -0
  162. package/dist/secrets/secrets.js.map +1 -0
  163. package/package.json +69 -0
  164. package/templates/access.md.eta +21 -0
  165. package/templates/demo/Dockerfile.eta +5 -0
  166. package/templates/demo/deploy.config.ts.eta +23 -0
  167. package/templates/demo/env.eta +2 -0
  168. package/templates/env-example.eta +6 -0
  169. package/templates/scaffold/Dockerfile.eta +7 -0
  170. package/templates/scaffold/deploy.config.selfhost.ts.eta +18 -0
  171. package/templates/scaffold/deploy.config.ts.eta +22 -0
  172. package/templates/scaffold/server.js.eta +9 -0
  173. package/templates/workflows/apply.yaml.eta +28 -0
  174. 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,3 @@
1
+ import { type CommandContext } from "@stricli/core";
2
+ export declare const planCommand: import("@stricli/core").Command<CommandContext>;
3
+ //# sourceMappingURL=plan.command.d.ts.map
@@ -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,3 @@
1
+ import { type CommandContext } from "@stricli/core";
2
+ export declare const resolveCommand: import("@stricli/core").Command<CommandContext>;
3
+ //# sourceMappingURL=resolve.command.d.ts.map
@@ -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,3 @@
1
+ import { type CommandContext } from "@stricli/core";
2
+ export declare const restore: import("@stricli/core").Command<CommandContext>;
3
+ //# sourceMappingURL=restore.command.d.ts.map
@@ -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,3 @@
1
+ import { type CommandContext } from "@stricli/core";
2
+ export declare const sandboxTunnel: import("@stricli/core").Command<CommandContext>;
3
+ //# sourceMappingURL=sandbox-tunnel.command.d.ts.map
@@ -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"}