@mp-lb/arcnet 0.0.0-stage → 0.2.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 +48 -2
- package/dist/addDependency.d.ts +3 -0
- package/dist/addDependency.d.ts.map +1 -0
- package/dist/addDependency.js +29 -0
- package/dist/addDependency.js.map +1 -0
- package/dist/apiClient.d.ts +3 -0
- package/dist/apiClient.d.ts.map +1 -0
- package/dist/apiClient.js +39 -0
- package/dist/apiClient.js.map +1 -0
- package/dist/checkIdentity.d.ts +3 -0
- package/dist/checkIdentity.d.ts.map +1 -0
- package/dist/checkIdentity.js +9 -0
- package/dist/checkIdentity.js.map +1 -0
- package/dist/ciOutputs.d.ts +2 -0
- package/dist/ciOutputs.d.ts.map +1 -0
- package/dist/ciOutputs.js +31 -0
- package/dist/ciOutputs.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -0
- package/dist/createCli.d.ts +3 -0
- package/dist/createCli.d.ts.map +1 -0
- package/dist/createCli.js +90 -0
- package/dist/createCli.js.map +1 -0
- package/dist/createProject.d.ts +26 -0
- package/dist/createProject.d.ts.map +1 -0
- package/dist/createProject.js +35 -0
- package/dist/createProject.js.map +1 -0
- package/dist/createSetupCommand.d.ts +3 -0
- package/dist/createSetupCommand.d.ts.map +1 -0
- package/dist/createSetupCommand.js +11 -0
- package/dist/createSetupCommand.js.map +1 -0
- package/dist/deploy.d.ts +3 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +47 -0
- package/dist/deploy.js.map +1 -0
- package/dist/fail.d.ts +2 -0
- package/dist/fail.d.ts.map +1 -0
- package/dist/fail.js +4 -0
- package/dist/fail.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/inspectReferences.d.ts +3 -0
- package/dist/inspectReferences.d.ts.map +1 -0
- package/dist/inspectReferences.js +10 -0
- package/dist/inspectReferences.js.map +1 -0
- package/dist/inspectStaticTree.d.ts +2 -0
- package/dist/inspectStaticTree.d.ts.map +1 -0
- package/dist/inspectStaticTree.js +17 -0
- package/dist/inspectStaticTree.js.map +1 -0
- package/dist/packageInfo.d.ts +3 -0
- package/dist/packageInfo.d.ts.map +1 -0
- package/dist/packageInfo.js +9 -0
- package/dist/packageInfo.js.map +1 -0
- package/dist/parseSelection.d.ts +3 -0
- package/dist/parseSelection.d.ts.map +1 -0
- package/dist/parseSelection.js +13 -0
- package/dist/parseSelection.js.map +1 -0
- package/dist/parseSetupInput.d.ts +16 -0
- package/dist/parseSetupInput.d.ts.map +1 -0
- package/dist/parseSetupInput.js +34 -0
- package/dist/parseSetupInput.js.map +1 -0
- package/dist/readSelection.d.ts +15 -0
- package/dist/readSelection.d.ts.map +1 -0
- package/dist/readSelection.js +36 -0
- package/dist/readSelection.js.map +1 -0
- package/dist/renderPlan.d.ts +27 -0
- package/dist/renderPlan.d.ts.map +1 -0
- package/dist/renderPlan.js +25 -0
- package/dist/renderPlan.js.map +1 -0
- package/dist/renderResult.d.ts +5 -0
- package/dist/renderResult.d.ts.map +1 -0
- package/dist/renderResult.js +15 -0
- package/dist/renderResult.js.map +1 -0
- package/dist/resolveRepository.d.ts +2 -0
- package/dist/resolveRepository.d.ts.map +1 -0
- package/dist/resolveRepository.js +24 -0
- package/dist/resolveRepository.js.map +1 -0
- package/dist/runProcess.d.ts +2 -0
- package/dist/runProcess.d.ts.map +1 -0
- package/dist/runProcess.js +16 -0
- package/dist/runProcess.js.map +1 -0
- package/dist/runTerraform.d.ts +8 -0
- package/dist/runTerraform.d.ts.map +1 -0
- package/dist/runTerraform.js +111 -0
- package/dist/runTerraform.js.map +1 -0
- package/dist/runVercel.d.ts +34 -0
- package/dist/runVercel.d.ts.map +1 -0
- package/dist/runVercel.js +52 -0
- package/dist/runVercel.js.map +1 -0
- package/dist/safePath.d.ts +2 -0
- package/dist/safePath.d.ts.map +1 -0
- package/dist/safePath.js +35 -0
- package/dist/safePath.js.map +1 -0
- package/dist/safeTargetPath.d.ts +2 -0
- package/dist/safeTargetPath.d.ts.map +1 -0
- package/dist/safeTargetPath.js +29 -0
- package/dist/safeTargetPath.js.map +1 -0
- package/dist/schemas.d.ts +106 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +85 -0
- package/dist/schemas.js.map +1 -0
- package/dist/secrets/assertNewSource.d.ts +3 -0
- package/dist/secrets/assertNewSource.d.ts.map +1 -0
- package/dist/secrets/assertNewSource.js +32 -0
- package/dist/secrets/assertNewSource.js.map +1 -0
- package/dist/secrets/config.d.ts +37 -0
- package/dist/secrets/config.d.ts.map +1 -0
- package/dist/secrets/config.js +67 -0
- package/dist/secrets/config.js.map +1 -0
- package/dist/secrets/createSecretsCommands.d.ts +3 -0
- package/dist/secrets/createSecretsCommands.d.ts.map +1 -0
- package/dist/secrets/createSecretsCommands.js +93 -0
- package/dist/secrets/createSecretsCommands.js.map +1 -0
- package/dist/secrets/loadSecrets.d.ts +3 -0
- package/dist/secrets/loadSecrets.d.ts.map +1 -0
- package/dist/secrets/loadSecrets.js +35 -0
- package/dist/secrets/loadSecrets.js.map +1 -0
- package/dist/secrets/promptPassword.d.ts +2 -0
- package/dist/secrets/promptPassword.d.ts.map +1 -0
- package/dist/secrets/promptPassword.js +42 -0
- package/dist/secrets/promptPassword.js.map +1 -0
- package/dist/secrets/provisionSource.d.ts +25 -0
- package/dist/secrets/provisionSource.d.ts.map +1 -0
- package/dist/secrets/provisionSource.js +141 -0
- package/dist/secrets/provisionSource.js.map +1 -0
- package/dist/secrets/readRemoteSource.d.ts +7 -0
- package/dist/secrets/readRemoteSource.d.ts.map +1 -0
- package/dist/secrets/readRemoteSource.js +32 -0
- package/dist/secrets/readRemoteSource.js.map +1 -0
- package/dist/secrets/runWithSecrets.d.ts +6 -0
- package/dist/secrets/runWithSecrets.d.ts.map +1 -0
- package/dist/secrets/runWithSecrets.js +59 -0
- package/dist/secrets/runWithSecrets.js.map +1 -0
- package/dist/secrets/secretCommand.d.ts +2 -0
- package/dist/secrets/secretCommand.d.ts.map +1 -0
- package/dist/secrets/secretCommand.js +17 -0
- package/dist/secrets/secretCommand.js.map +1 -0
- package/dist/secrets/selectSecrets.d.ts +3 -0
- package/dist/secrets/selectSecrets.d.ts.map +1 -0
- package/dist/secrets/selectSecrets.js +18 -0
- package/dist/secrets/selectSecrets.js.map +1 -0
- package/dist/secrets/syncSecrets.d.ts +10 -0
- package/dist/secrets/syncSecrets.d.ts.map +1 -0
- package/dist/secrets/syncSecrets.js +43 -0
- package/dist/secrets/syncSecrets.js.map +1 -0
- package/dist/secrets/wireSecretsWorkflows.d.ts +2 -0
- package/dist/secrets/wireSecretsWorkflows.d.ts.map +1 -0
- package/dist/secrets/wireSecretsWorkflows.js +48 -0
- package/dist/secrets/wireSecretsWorkflows.js.map +1 -0
- package/dist/secrets/withDeploymentSecrets.d.ts +2 -0
- package/dist/secrets/withDeploymentSecrets.d.ts.map +1 -0
- package/dist/secrets/withDeploymentSecrets.js +58 -0
- package/dist/secrets/withDeploymentSecrets.js.map +1 -0
- package/dist/secrets/writeSecretsWorkflow.d.ts +3 -0
- package/dist/secrets/writeSecretsWorkflow.d.ts.map +1 -0
- package/dist/secrets/writeSecretsWorkflow.js +60 -0
- package/dist/secrets/writeSecretsWorkflow.js.map +1 -0
- package/dist/selectNetwork.d.ts +26 -0
- package/dist/selectNetwork.d.ts.map +1 -0
- package/dist/selectNetwork.js +48 -0
- package/dist/selectNetwork.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +192 -0
- package/dist/setup.js.map +1 -0
- package/dist/setupReport.d.ts +8 -0
- package/dist/setupReport.d.ts.map +1 -0
- package/dist/setupReport.js +2 -0
- package/dist/setupReport.js.map +1 -0
- package/dist/setupVercel.d.ts +9 -0
- package/dist/setupVercel.d.ts.map +1 -0
- package/dist/setupVercel.js +72 -0
- package/dist/setupVercel.js.map +1 -0
- package/dist/stageSite.d.ts +3 -0
- package/dist/stageSite.d.ts.map +1 -0
- package/dist/stageSite.js +31 -0
- package/dist/stageSite.js.map +1 -0
- package/dist/validateConfig.d.ts +3 -0
- package/dist/validateConfig.d.ts.map +1 -0
- package/dist/validateConfig.js +17 -0
- package/dist/validateConfig.js.map +1 -0
- package/docs/public/commands.md +132 -0
- package/docs/public/llms-full.txt +182 -0
- package/package.json +50 -3
- package/src/addDependency.ts +41 -0
- package/src/apiClient.ts +51 -0
- package/src/checkIdentity.ts +18 -0
- package/src/ciOutputs.ts +47 -0
- package/src/cli.ts +11 -0
- package/src/createCli.ts +128 -0
- package/src/createProject.ts +66 -0
- package/src/createSetupCommand.ts +16 -0
- package/src/deploy.ts +71 -0
- package/src/fail.ts +3 -0
- package/src/index.ts +2 -0
- package/src/inspectReferences.ts +20 -0
- package/src/inspectStaticTree.ts +19 -0
- package/src/packageInfo.ts +10 -0
- package/src/parseSelection.ts +22 -0
- package/src/parseSetupInput.ts +40 -0
- package/src/readSelection.ts +47 -0
- package/src/renderPlan.ts +27 -0
- package/src/renderResult.ts +18 -0
- package/src/resolveRepository.ts +38 -0
- package/src/runProcess.ts +26 -0
- package/src/runTerraform.ts +182 -0
- package/src/runVercel.ts +77 -0
- package/src/safePath.ts +43 -0
- package/src/safeTargetPath.ts +32 -0
- package/src/schemas.ts +126 -0
- package/src/secrets/assertNewSource.ts +40 -0
- package/src/secrets/config.ts +91 -0
- package/src/secrets/createSecretsCommands.ts +189 -0
- package/src/secrets/loadSecrets.ts +53 -0
- package/src/secrets/promptPassword.ts +46 -0
- package/src/secrets/provisionSource.ts +238 -0
- package/src/secrets/readRemoteSource.ts +73 -0
- package/src/secrets/runWithSecrets.ts +71 -0
- package/src/secrets/secretCommand.ts +26 -0
- package/src/secrets/selectSecrets.ts +33 -0
- package/src/secrets/syncSecrets.ts +60 -0
- package/src/secrets/wireSecretsWorkflows.ts +57 -0
- package/src/secrets/withDeploymentSecrets.ts +77 -0
- package/src/secrets/writeSecretsWorkflow.ts +83 -0
- package/src/selectNetwork.ts +73 -0
- package/src/setup.ts +277 -0
- package/src/setupReport.ts +11 -0
- package/src/setupVercel.ts +126 -0
- package/src/stageSite.ts +54 -0
- package/src/validateConfig.ts +22 -0
- package/templates/deploy-arc.yaml +73 -0
- package/templates/deploy-vercel.yaml +43 -0
- package/templates/network.yaml +105 -0
- package/templates/vercel-static/main.tf +128 -0
- package/templates/vercel-static/module.yaml +51 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# ArcNet command reference
|
|
2
|
+
|
|
3
|
+
Generated from the CLI command tree.
|
|
4
|
+
|
|
5
|
+
## Global Options
|
|
6
|
+
|
|
7
|
+
| Option | Description |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `-V, --version` | output the version number |
|
|
10
|
+
| `--root <directory>` | Target project root |
|
|
11
|
+
| `--json` | Render one JSON result |
|
|
12
|
+
| `--jsonl` | Render structured completion events |
|
|
13
|
+
| `--noninteractive` | Run without prompts (all commands are noninteractive) |
|
|
14
|
+
|
|
15
|
+
## `arcnet env`
|
|
16
|
+
|
|
17
|
+
Load ordered encrypted Forum sources and select environment values.
|
|
18
|
+
|
|
19
|
+
### `arcnet env check`
|
|
20
|
+
|
|
21
|
+
Validate decryption and mappings; report key names only.
|
|
22
|
+
|
|
23
|
+
| Option | Description |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `--config <file>` | Secrets source configuration |
|
|
26
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
27
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
28
|
+
|
|
29
|
+
### `arcnet env export`
|
|
30
|
+
|
|
31
|
+
Write selected plaintext JSON to stdout for an explicit pipeline.
|
|
32
|
+
|
|
33
|
+
| Option | Description |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `--config <file>` | Secrets source configuration |
|
|
36
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
37
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
38
|
+
|
|
39
|
+
### `arcnet env run <command...>`
|
|
40
|
+
|
|
41
|
+
Run a command with selected keys only; withhold child output.
|
|
42
|
+
|
|
43
|
+
| Option | Description |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `--config <file>` | Secrets source configuration |
|
|
46
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
47
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
48
|
+
|
|
49
|
+
## `arcnet secrets`
|
|
50
|
+
|
|
51
|
+
Attach Forum files, provision GitHub keys and refresh encrypted snapshots.
|
|
52
|
+
|
|
53
|
+
### `arcnet secrets add`
|
|
54
|
+
|
|
55
|
+
Attach an existing Forum file and provision its CI key.
|
|
56
|
+
|
|
57
|
+
| Option | Description |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `--name <name>` | Unique source name; sources merge in installation order |
|
|
60
|
+
| `--store <workspace/store>` | Forum store |
|
|
61
|
+
| `--path <path>` | Encrypted file path in Forum |
|
|
62
|
+
| `--key-env <name>` | GitHub repository secret / environment variable for this file's key |
|
|
63
|
+
| `--repository <owner/repo>` | GitHub repository receiving the key |
|
|
64
|
+
| `--config <file>` | Secrets source configuration |
|
|
65
|
+
| `--existing-key` | Reuse an existing GitHub secret without creating a recipient |
|
|
66
|
+
|
|
67
|
+
### `arcnet secrets init`
|
|
68
|
+
|
|
69
|
+
Create a Forum secrets file, prompt for your password and provision its CI key.
|
|
70
|
+
|
|
71
|
+
| Option | Description |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `--name <name>` | Unique source name; sources merge in installation order |
|
|
74
|
+
| `--store <workspace/store>` | Forum store |
|
|
75
|
+
| `--path <path>` | Encrypted file path in Forum |
|
|
76
|
+
| `--key-env <name>` | GitHub repository secret / environment variable for this file's key |
|
|
77
|
+
| `--repository <owner/repo>` | GitHub repository receiving the key |
|
|
78
|
+
| `--config <file>` | Secrets source configuration |
|
|
79
|
+
| `--input <file>` | Initial plaintext JSON file; defaults to an empty object |
|
|
80
|
+
|
|
81
|
+
### `arcnet secrets sync`
|
|
82
|
+
|
|
83
|
+
Refresh encrypted snapshots from Forum and regenerate validation CI; no decryption.
|
|
84
|
+
|
|
85
|
+
| Option | Description |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `--config <file>` | Secrets source configuration |
|
|
88
|
+
|
|
89
|
+
## `arcnet version`
|
|
90
|
+
|
|
91
|
+
Show the installed package version.
|
|
92
|
+
|
|
93
|
+
## `arcnet setup <slug>`
|
|
94
|
+
|
|
95
|
+
Add ArcNet configuration and workflow; pin the CLI in the project manifest.
|
|
96
|
+
|
|
97
|
+
| Option | Description |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `--dry-run` | Report generated files without writing |
|
|
100
|
+
| `--service <name>` | Default container service |
|
|
101
|
+
| `--dockerfile <path>` | Container Dockerfile |
|
|
102
|
+
| `--repository <owner/repo>` | GitHub repository (defaults to origin) |
|
|
103
|
+
| `--services <path>` | Explicit service selection JSON |
|
|
104
|
+
| `--vercel <path>` | Static Vercel references JSON |
|
|
105
|
+
|
|
106
|
+
## `arcnet check`
|
|
107
|
+
|
|
108
|
+
Validate project configuration offline.
|
|
109
|
+
|
|
110
|
+
## `arcnet plan`
|
|
111
|
+
|
|
112
|
+
Plan deployment (Terraform contacts providers; static Vercel stays offline).
|
|
113
|
+
|
|
114
|
+
## `arcnet deploy`
|
|
115
|
+
|
|
116
|
+
Deploy the approved project.
|
|
117
|
+
|
|
118
|
+
## `arcnet preview`
|
|
119
|
+
|
|
120
|
+
Deploy static Vercel sites to preview.
|
|
121
|
+
|
|
122
|
+
## `arcnet inspect`
|
|
123
|
+
|
|
124
|
+
Verify static Vercel project identities remotely.
|
|
125
|
+
|
|
126
|
+
## `arcnet create <site>`
|
|
127
|
+
|
|
128
|
+
Create one explicitly approved Vercel project.
|
|
129
|
+
|
|
130
|
+
## `arcnet ci`
|
|
131
|
+
|
|
132
|
+
Validate deployment identity and write GitHub Actions outputs.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# @mp-lb/arcnet
|
|
2
|
+
|
|
3
|
+
ArcNet's TypeScript CLI for installing deployment configuration and deploying projects. The package owns shared runners, validation, workflow templates and the Vercel Terraform module; projects keep configuration and application-specific Dockerfiles.
|
|
4
|
+
|
|
5
|
+
From an existing project with Zap, GitHub, and pinned pnpm:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm dlx @mp-lb/arcnet@0.2.0 setup hello-world --dry-run
|
|
9
|
+
pnpm dlx @mp-lb/arcnet@0.2.0 setup hello-world
|
|
10
|
+
pnpm install
|
|
11
|
+
pnpm exec arcnet check
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Setup pins this package in the existing root manifest. Commit the resulting lockfile. Deployment starts disabled, and setup never provisions cloud resources. Upgrades use the project's normal dependency workflow.
|
|
15
|
+
|
|
16
|
+
[Project setup](https://github.com/mp-lb/stackforge/blob/main/arcnet/SETUP.md) · [Environment setup](https://github.com/mp-lb/stackforge/blob/main/arcnet/environment/setup.md) · [Audit](https://github.com/mp-lb/stackforge/blob/main/arcnet/AUDIT.md) · [Command reference](docs/public/commands.md)
|
|
17
|
+
|
|
18
|
+
Zap Arc remains the pinned Terraform engine dependency. Environment bootstrap, health checks and teardown are not implemented by this package yet. The static Vercel adapter retains its existing static-only and explicit-project-reference limitations.
|
|
19
|
+
|
|
20
|
+
## Layered secrets
|
|
21
|
+
|
|
22
|
+
`arcnet secrets add` attaches an existing Forum encrypted JSON file. `arcnet secrets init` creates one. Both register a file-specific decryption key in the selected GitHub repository, save an encrypted snapshot, and generate a validation workflow. Setup prompts for your Forum encryption password locally; it never prints the password or recipient key. Use `--existing-key` when the GitHub secret already exists. The local `fm` and `gh` CLIs must be authenticated; the selected Forum parent directory must exist.
|
|
23
|
+
|
|
24
|
+
The project keeps only `.arcnet/secrets.json`, encrypted snapshots under `.arcnet/secrets/`, and workflow references. Sources merge left to right, with later values winning. Each source names its own key environment variable. JSON must be an object; unused structured values are allowed, while selected environment values must be nonempty strings. Consumer mappings select and rename fields; an array of source names accepts aliases only when their values agree.
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"version": 1,
|
|
29
|
+
"repository": "example/hello-world",
|
|
30
|
+
"sources": [
|
|
31
|
+
{ "name": "standard", "store": "example/company", "path": "/admin/standard.json.enc", "keyEnv": "STANDARD_SECRETS_KEY" },
|
|
32
|
+
{ "name": "project", "store": "example/company", "path": "/admin/hello-world.json.enc", "keyEnv": "PROJECT_SECRETS_KEY" }
|
|
33
|
+
],
|
|
34
|
+
"consumers": {
|
|
35
|
+
"publish": { "NODE_AUTH_TOKEN": ["NPM_TOKEN", "NODE_AUTH_TOKEN"] },
|
|
36
|
+
"deploy": { "VERCEL_TOKEN": "VERCEL_API_TOKEN" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`secrets sync` fetches ciphertext and adds snapshot identity, revision and checksum to this configuration. Commit config and ciphertext together. CI uses the reviewed snapshots and needs only each file's decryption key, not a Forum login. Sync after editing or rotating a source; obsolete snapshots can be removed after checking that no configuration references them. Setup/sync also wire source-key references into workflow steps that call ArcNet's env or deployment commands.
|
|
42
|
+
|
|
43
|
+
For live loading, omit a snapshot or select `--live`: the installed `fm` CLI fetches each source using its local login or the source's optional `tokenEnv` access credential. A decryption recipient is **not** a Forum read token. Live CI therefore needs an installed, authenticated `fm` as well as the independent decryption keys. Generated CI intentionally uses snapshots.
|
|
44
|
+
|
|
45
|
+
`arcnet env check` reports source names and selected key names, never values. `arcnet env export` explicitly emits selected plaintext JSON. `arcnet env run` gives a subprocess only the selected values and a small execution environment; it removes file keys, isolates temporary HOME/cache paths, and withholds subprocess output. Keep npm publishing mappings scoped to publishing credentials. The command reference documents the exact options.
|
|
46
|
+
|
|
47
|
+
When `.arcnet/secrets.json` exists, deployment commands automatically load it. The `deploy` consumer selects operator credentials; Terraform application values are selected using the existing service env lists in `zap.yaml`. No duplicated application map is required. Offline project checks remain offline. Secrets commands in GitHub Actions require the configured repository's main branch.
|
|
48
|
+
|
|
49
|
+
Provisioning modifies Forum and GitHub separately. A failed GitHub upload leaves an unused Forum recipient; rerun `secrets add` to create/upload another and remove the unused recipient later. If upload succeeded but snapshot/config writing failed, attach the file with `--existing-key`. Existing sources are not silently rotated on reruns. Provision while nobody else is editing that file: the current fm write interface does not offer atomic revision-conditional writes, though ArcNet checks identity/revision before updating and refuses occupied init paths. GitHub secret names are repository-scoped; environment-level overrides take precedence in jobs that use an environment.
|
|
50
|
+
|
|
51
|
+
# ArcNet command reference
|
|
52
|
+
|
|
53
|
+
Generated from the CLI command tree.
|
|
54
|
+
|
|
55
|
+
## Global Options
|
|
56
|
+
|
|
57
|
+
| Option | Description |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `-V, --version` | output the version number |
|
|
60
|
+
| `--root <directory>` | Target project root |
|
|
61
|
+
| `--json` | Render one JSON result |
|
|
62
|
+
| `--jsonl` | Render structured completion events |
|
|
63
|
+
| `--noninteractive` | Run without prompts (all commands are noninteractive) |
|
|
64
|
+
|
|
65
|
+
## `arcnet env`
|
|
66
|
+
|
|
67
|
+
Load ordered encrypted Forum sources and select environment values.
|
|
68
|
+
|
|
69
|
+
### `arcnet env check`
|
|
70
|
+
|
|
71
|
+
Validate decryption and mappings; report key names only.
|
|
72
|
+
|
|
73
|
+
| Option | Description |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `--config <file>` | Secrets source configuration |
|
|
76
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
77
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
78
|
+
|
|
79
|
+
### `arcnet env export`
|
|
80
|
+
|
|
81
|
+
Write selected plaintext JSON to stdout for an explicit pipeline.
|
|
82
|
+
|
|
83
|
+
| Option | Description |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `--config <file>` | Secrets source configuration |
|
|
86
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
87
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
88
|
+
|
|
89
|
+
### `arcnet env run <command...>`
|
|
90
|
+
|
|
91
|
+
Run a command with selected keys only; withhold child output.
|
|
92
|
+
|
|
93
|
+
| Option | Description |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `--config <file>` | Secrets source configuration |
|
|
96
|
+
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
97
|
+
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
98
|
+
|
|
99
|
+
## `arcnet secrets`
|
|
100
|
+
|
|
101
|
+
Attach Forum files, provision GitHub keys and refresh encrypted snapshots.
|
|
102
|
+
|
|
103
|
+
### `arcnet secrets add`
|
|
104
|
+
|
|
105
|
+
Attach an existing Forum file and provision its CI key.
|
|
106
|
+
|
|
107
|
+
| Option | Description |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `--name <name>` | Unique source name; sources merge in installation order |
|
|
110
|
+
| `--store <workspace/store>` | Forum store |
|
|
111
|
+
| `--path <path>` | Encrypted file path in Forum |
|
|
112
|
+
| `--key-env <name>` | GitHub repository secret / environment variable for this file's key |
|
|
113
|
+
| `--repository <owner/repo>` | GitHub repository receiving the key |
|
|
114
|
+
| `--config <file>` | Secrets source configuration |
|
|
115
|
+
| `--existing-key` | Reuse an existing GitHub secret without creating a recipient |
|
|
116
|
+
|
|
117
|
+
### `arcnet secrets init`
|
|
118
|
+
|
|
119
|
+
Create a Forum secrets file, prompt for your password and provision its CI key.
|
|
120
|
+
|
|
121
|
+
| Option | Description |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `--name <name>` | Unique source name; sources merge in installation order |
|
|
124
|
+
| `--store <workspace/store>` | Forum store |
|
|
125
|
+
| `--path <path>` | Encrypted file path in Forum |
|
|
126
|
+
| `--key-env <name>` | GitHub repository secret / environment variable for this file's key |
|
|
127
|
+
| `--repository <owner/repo>` | GitHub repository receiving the key |
|
|
128
|
+
| `--config <file>` | Secrets source configuration |
|
|
129
|
+
| `--input <file>` | Initial plaintext JSON file; defaults to an empty object |
|
|
130
|
+
|
|
131
|
+
### `arcnet secrets sync`
|
|
132
|
+
|
|
133
|
+
Refresh encrypted snapshots from Forum and regenerate validation CI; no decryption.
|
|
134
|
+
|
|
135
|
+
| Option | Description |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `--config <file>` | Secrets source configuration |
|
|
138
|
+
|
|
139
|
+
## `arcnet version`
|
|
140
|
+
|
|
141
|
+
Show the installed package version.
|
|
142
|
+
|
|
143
|
+
## `arcnet setup <slug>`
|
|
144
|
+
|
|
145
|
+
Add ArcNet configuration and workflow; pin the CLI in the project manifest.
|
|
146
|
+
|
|
147
|
+
| Option | Description |
|
|
148
|
+
| --- | --- |
|
|
149
|
+
| `--dry-run` | Report generated files without writing |
|
|
150
|
+
| `--service <name>` | Default container service |
|
|
151
|
+
| `--dockerfile <path>` | Container Dockerfile |
|
|
152
|
+
| `--repository <owner/repo>` | GitHub repository (defaults to origin) |
|
|
153
|
+
| `--services <path>` | Explicit service selection JSON |
|
|
154
|
+
| `--vercel <path>` | Static Vercel references JSON |
|
|
155
|
+
|
|
156
|
+
## `arcnet check`
|
|
157
|
+
|
|
158
|
+
Validate project configuration offline.
|
|
159
|
+
|
|
160
|
+
## `arcnet plan`
|
|
161
|
+
|
|
162
|
+
Plan deployment (Terraform contacts providers; static Vercel stays offline).
|
|
163
|
+
|
|
164
|
+
## `arcnet deploy`
|
|
165
|
+
|
|
166
|
+
Deploy the approved project.
|
|
167
|
+
|
|
168
|
+
## `arcnet preview`
|
|
169
|
+
|
|
170
|
+
Deploy static Vercel sites to preview.
|
|
171
|
+
|
|
172
|
+
## `arcnet inspect`
|
|
173
|
+
|
|
174
|
+
Verify static Vercel project identities remotely.
|
|
175
|
+
|
|
176
|
+
## `arcnet create <site>`
|
|
177
|
+
|
|
178
|
+
Create one explicitly approved Vercel project.
|
|
179
|
+
|
|
180
|
+
## `arcnet ci`
|
|
181
|
+
|
|
182
|
+
Validate deployment identity and write GitHub Actions outputs.
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mp-lb/arcnet",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "ArcNet project installation and deployment CLI.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"arcnet": "./dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"templates",
|
|
24
|
+
"README.md",
|
|
25
|
+
"docs/public",
|
|
26
|
+
"src"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/mp-lb/tools.git",
|
|
31
|
+
"directory": "packages/arcnet"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@mp-lb/forum-secrets": "0.2.1",
|
|
38
|
+
"@mp-lb/zapper": "0.21.0",
|
|
39
|
+
"commander": "14.0.3",
|
|
40
|
+
"yaml": "2.8.1",
|
|
41
|
+
"zod": "4.4.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@mp-lb/cli-docs": "0.0.1"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "rm -rf dist && tsc --project tsconfig.json && chmod +x dist/cli.js",
|
|
48
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
49
|
+
"test": "pnpm build && node --import tsx --test test/*.test.ts && pnpm docs:check",
|
|
50
|
+
"docs:gen": "pnpm --filter @mp-lb/cli-docs build && tsx scripts/generateDocs.ts",
|
|
51
|
+
"docs:check": "pnpm --filter @mp-lb/cli-docs build && tsx scripts/generateDocs.ts --check"
|
|
52
|
+
}
|
|
6
53
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { packageVersion } from "./packageInfo.js";
|
|
5
|
+
|
|
6
|
+
const manifestSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
dependencies: z.record(z.string(), z.string()).optional(),
|
|
9
|
+
devDependencies: z.record(z.string(), z.string()).optional(),
|
|
10
|
+
})
|
|
11
|
+
.passthrough();
|
|
12
|
+
|
|
13
|
+
export const addDependency = (path: string) => {
|
|
14
|
+
const manifest = manifestSchema.parse(JSON.parse(readFileSync(path, "utf8")));
|
|
15
|
+
|
|
16
|
+
const existing =
|
|
17
|
+
manifest.dependencies?.["@mp-lb/arcnet"] ??
|
|
18
|
+
manifest.devDependencies?.["@mp-lb/arcnet"];
|
|
19
|
+
|
|
20
|
+
if (existing && existing !== packageVersion)
|
|
21
|
+
throw new Error(
|
|
22
|
+
"Existing ArcNet dependency differs; review its version before setup.",
|
|
23
|
+
);
|
|
24
|
+
if (!manifest.dependencies?.["@mp-lb/arcnet"])
|
|
25
|
+
manifest.devDependencies = {
|
|
26
|
+
...manifest.devDependencies,
|
|
27
|
+
"@mp-lb/arcnet": packageVersion,
|
|
28
|
+
};
|
|
29
|
+
return JSON.stringify(manifest, null, 2) + "\n";
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const hasDependency = (root: string) => {
|
|
33
|
+
const manifest = manifestSchema.parse(
|
|
34
|
+
JSON.parse(readFileSync(join(root, "package.json"), "utf8")),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return Boolean(
|
|
38
|
+
manifest.dependencies?.["@mp-lb/arcnet"] ??
|
|
39
|
+
manifest.devDependencies?.["@mp-lb/arcnet"],
|
|
40
|
+
);
|
|
41
|
+
};
|
package/src/apiClient.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { fail } from "./fail.js";
|
|
2
|
+
import type { VercelRequest } from "./schemas.js";
|
|
3
|
+
import { vercelResponseSchema } from "./schemas.js";
|
|
4
|
+
|
|
5
|
+
export const apiClient = (
|
|
6
|
+
token: string | undefined,
|
|
7
|
+
fetcher: typeof fetch = fetch,
|
|
8
|
+
): VercelRequest => {
|
|
9
|
+
if (!token)
|
|
10
|
+
fail(
|
|
11
|
+
"VERCEL_TOKEN is required for remote operations; check and plan remain offline.",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
return async (method, path, account, body) => {
|
|
15
|
+
const url = new URL(path, "https://api.vercel.com");
|
|
16
|
+
if (account.type === "team") url.searchParams.set("teamId", account.id);
|
|
17
|
+
let response;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
response = await fetcher(url, {
|
|
21
|
+
method,
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${token}`,
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
},
|
|
26
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
27
|
+
signal: AbortSignal.timeout(30000),
|
|
28
|
+
});
|
|
29
|
+
} catch {
|
|
30
|
+
fail(
|
|
31
|
+
method === "POST"
|
|
32
|
+
? "Creation outcome uncertain. Inspect the named project before retrying; no automatic retry was attempted."
|
|
33
|
+
: "Vercel read failed; no changes attempted.",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (response.status === 404 && method === "GET") return null;
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
fail(
|
|
40
|
+
`Vercel ${method} failed (HTTP ${response.status}). Check scope/access; response content omitted.`,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
return vercelResponseSchema.parse(await response.json());
|
|
45
|
+
} catch {
|
|
46
|
+
fail(
|
|
47
|
+
"Vercel returned an invalid response; inspect the project before retrying.",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { fail } from "./fail.js";
|
|
2
|
+
import type { VercelAccount, VercelResponse, VercelSite } from "./schemas.js";
|
|
3
|
+
|
|
4
|
+
export const checkIdentity = (
|
|
5
|
+
project: VercelResponse | null,
|
|
6
|
+
site: VercelSite,
|
|
7
|
+
account: VercelAccount,
|
|
8
|
+
) => {
|
|
9
|
+
if (
|
|
10
|
+
!project ||
|
|
11
|
+
project.id !== site.projectId ||
|
|
12
|
+
project.name !== site.projectName ||
|
|
13
|
+
project.accountId !== account.id
|
|
14
|
+
)
|
|
15
|
+
fail(
|
|
16
|
+
`Project identity/scope mismatch for ${site.projectName}. No deployment attempted.`,
|
|
17
|
+
);
|
|
18
|
+
};
|
package/src/ciOutputs.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { terraformConfigSchema } from "./schemas.js";
|
|
6
|
+
import { validateConfig } from "./validateConfig.js";
|
|
7
|
+
|
|
8
|
+
export const ciOutputs = (root: string): Record<string, string> => {
|
|
9
|
+
const input: unknown = JSON.parse(
|
|
10
|
+
readFileSync(join(root, ".arcnet/project.json"), "utf8"),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
z.object({ mode: z.string().optional() }).parse(input).mode === "vercel"
|
|
15
|
+
) {
|
|
16
|
+
const c = validateConfig(input, root);
|
|
17
|
+
return {
|
|
18
|
+
approved: String(
|
|
19
|
+
c.approved &&
|
|
20
|
+
Object.values(c.sites).every((s) => s.mode === "existing"),
|
|
21
|
+
),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const c = terraformConfigSchema.parse(input);
|
|
26
|
+
|
|
27
|
+
const n = z
|
|
28
|
+
.object({ region: z.string().regex(/^[a-z]+-[a-z]+[0-9]$/) })
|
|
29
|
+
.parse(parse(readFileSync(join(root, ".arcnet/network.yaml"), "utf8")));
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
c.approved &&
|
|
33
|
+
(!/^projects\/\d+\/locations\/global\/workloadIdentityPools\/github\/providers\/github-actions$/.test(
|
|
34
|
+
c.workloadIdentityProvider,
|
|
35
|
+
) ||
|
|
36
|
+
!/^arc-deploy@[a-z][a-z0-9-]+\.iam\.gserviceaccount\.com$/.test(
|
|
37
|
+
c.serviceAccount,
|
|
38
|
+
))
|
|
39
|
+
)
|
|
40
|
+
throw new Error("Complete WIF configuration before approval.");
|
|
41
|
+
return {
|
|
42
|
+
approved: String(c.approved),
|
|
43
|
+
provider: c.approved ? c.workloadIdentityProvider : "",
|
|
44
|
+
account: c.approved ? c.serviceAccount : "",
|
|
45
|
+
registry: `${n.region}-docker.pkg.dev`,
|
|
46
|
+
};
|
|
47
|
+
};
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createCli } from "./createCli.js";
|
|
3
|
+
await createCli()
|
|
4
|
+
.parseAsync()
|
|
5
|
+
.catch((error: unknown) => {
|
|
6
|
+
process.stderr.write(
|
|
7
|
+
`ArcNet: ${error instanceof Error ? error.message : "Command failed"}\n`,
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
});
|
package/src/createCli.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { appendFileSync, readFileSync, realpathSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { ciOutputs } from "./ciOutputs.js";
|
|
6
|
+
import { createSetupCommand } from "./createSetupCommand.js";
|
|
7
|
+
import { packageVersion } from "./packageInfo.js";
|
|
8
|
+
import { renderResult } from "./renderResult.js";
|
|
9
|
+
import { runTerraform } from "./runTerraform.js";
|
|
10
|
+
import { runVercel } from "./runVercel.js";
|
|
11
|
+
import { setup } from "./setup.js";
|
|
12
|
+
import { createSecretsCommands } from "./secrets/createSecretsCommands.js";
|
|
13
|
+
import { withDeploymentSecrets } from "./secrets/withDeploymentSecrets.js";
|
|
14
|
+
|
|
15
|
+
export const createCli = () => {
|
|
16
|
+
const cli = new Command("arcnet")
|
|
17
|
+
.description("Install and deploy ArcNet projects.")
|
|
18
|
+
.version(packageVersion)
|
|
19
|
+
.option("--root <directory>", "Target project root", process.cwd())
|
|
20
|
+
.option("--json", "Render one JSON result")
|
|
21
|
+
.option("--jsonl", "Render structured completion events")
|
|
22
|
+
.option(
|
|
23
|
+
"--noninteractive",
|
|
24
|
+
"Run without prompts (all commands are noninteractive)",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
cli.hook("preAction", () => {
|
|
28
|
+
if (cli.opts().json && cli.opts().jsonl)
|
|
29
|
+
throw new Error("Choose either --json or --jsonl.");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const output = (result: unknown) => {
|
|
33
|
+
process.stdout.write(renderResult(result, cli.opts()) + "\n");
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
createSecretsCommands(cli, output);
|
|
37
|
+
|
|
38
|
+
cli
|
|
39
|
+
.command("version")
|
|
40
|
+
.description("Show the installed package version.")
|
|
41
|
+
.action(() => output({ version: packageVersion }));
|
|
42
|
+
|
|
43
|
+
const install = createSetupCommand();
|
|
44
|
+
install.action(() =>
|
|
45
|
+
output({
|
|
46
|
+
...setup(
|
|
47
|
+
install.args.concat(
|
|
48
|
+
install.options.flatMap((option) => {
|
|
49
|
+
const key = option.attributeName();
|
|
50
|
+
if (install.getOptionValueSource(key) !== "cli") return [];
|
|
51
|
+
const value: unknown = install.opts()[key];
|
|
52
|
+
return value === true
|
|
53
|
+
? [option.long!]
|
|
54
|
+
: [option.long!, String(value)];
|
|
55
|
+
}),
|
|
56
|
+
),
|
|
57
|
+
realpathSync(cli.opts().root),
|
|
58
|
+
),
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
cli.addCommand(install);
|
|
63
|
+
|
|
64
|
+
for (const [name, description] of Object.entries({
|
|
65
|
+
check: "Validate project configuration offline.",
|
|
66
|
+
plan: "Plan deployment (Terraform contacts providers; static Vercel stays offline).",
|
|
67
|
+
deploy: "Deploy the approved project.",
|
|
68
|
+
preview: "Deploy static Vercel sites to preview.",
|
|
69
|
+
inspect: "Verify static Vercel project identities remotely.",
|
|
70
|
+
create: "Create one explicitly approved Vercel project.",
|
|
71
|
+
})) {
|
|
72
|
+
const command = cli.command(name).description(description);
|
|
73
|
+
if (name === "create") command.argument("<site>", "Configured site name");
|
|
74
|
+
command.action(async (site: unknown) => {
|
|
75
|
+
const root = realpathSync(cli.opts().root);
|
|
76
|
+
|
|
77
|
+
const mode = z
|
|
78
|
+
.object({ mode: z.string().optional() })
|
|
79
|
+
.parse(
|
|
80
|
+
JSON.parse(readFileSync(join(root, ".arcnet/project.json"), "utf8")),
|
|
81
|
+
).mode;
|
|
82
|
+
|
|
83
|
+
const machine = Boolean(cli.opts().json || cli.opts().jsonl);
|
|
84
|
+
|
|
85
|
+
const execute = async () => {
|
|
86
|
+
if (mode === "vercel")
|
|
87
|
+
return runVercel(
|
|
88
|
+
name,
|
|
89
|
+
root,
|
|
90
|
+
typeof site === "string" ? site : undefined,
|
|
91
|
+
machine,
|
|
92
|
+
);
|
|
93
|
+
if (name === "check" || name === "plan" || name === "deploy")
|
|
94
|
+
return runTerraform(name, root, machine);
|
|
95
|
+
throw new Error(
|
|
96
|
+
`${name} is only supported for static Vercel references.`,
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
output(
|
|
101
|
+
await (name === "check" || (name === "plan" && mode === "vercel")
|
|
102
|
+
? execute()
|
|
103
|
+
: withDeploymentSecrets(root, mode, execute)),
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cli
|
|
109
|
+
.command("ci")
|
|
110
|
+
.description(
|
|
111
|
+
"Validate deployment identity and write GitHub Actions outputs.",
|
|
112
|
+
)
|
|
113
|
+
.action(() => {
|
|
114
|
+
const outputs = ciOutputs(realpathSync(cli.opts().root));
|
|
115
|
+
if (!process.env.GITHUB_OUTPUT)
|
|
116
|
+
throw new Error("GITHUB_OUTPUT is required for the ci command.");
|
|
117
|
+
appendFileSync(
|
|
118
|
+
process.env.GITHUB_OUTPUT,
|
|
119
|
+
Object.entries(outputs)
|
|
120
|
+
.map(([key, value]) => `${key}=${value}\n`)
|
|
121
|
+
.join(""),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
output(outputs);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return cli;
|
|
128
|
+
};
|