@devrouter/cli 0.5.5 → 0.6.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 +13 -2
- package/assets/preview/github-sweep.yml +23 -0
- package/assets/preview/github.yml +35 -0
- package/assets/preview/gitlab-template.yml +34 -0
- package/assets/preview/gitlab.yml +22 -0
- package/assets/preview/installation.json +54 -0
- package/bin/devrouter-process +29 -2
- package/dist/devrouter-lifecycle-worker.js +1554 -425
- package/dist/devrouter-preview-gitlab-ingress.js +182 -0
- package/dist/devrouter.js +9442 -2701
- package/package.json +11 -2
- package/upgrade-prompts/0.5.6.md +73 -0
- package/upgrade-prompts/0.6.0.md +57 -0
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ can share their standard ports through TLS/SNI hostname routing.
|
|
|
8
8
|
|
|
9
9
|
## What devrouter owns
|
|
10
10
|
|
|
11
|
-
- One strict
|
|
11
|
+
- One strict local routing/profile configuration: `.devrouter.yml`.
|
|
12
|
+
- Opt-in remote previews in `.devrouter.preview.yml`, with reviewed GitHub/GitLab controller source and Northflank qualification gates.
|
|
12
13
|
- Machine setup, the shared `devnet` network, Traefik, local TLS, and route state.
|
|
13
14
|
- Host, Docker, proxy, and dependency-only application definitions.
|
|
14
15
|
- Exact-checkout devcontainer workspace lifecycle (DevPod or Devsy) for primary and linked Git worktrees.
|
|
@@ -82,6 +83,14 @@ Dev Container clients still see the full source configuration. Check
|
|
|
82
83
|
`devrouter status` or `devrouter doctor` when you need the desired, active, and
|
|
83
84
|
drift state.
|
|
84
85
|
|
|
86
|
+
Managed repositories can also declare a separate runtime variant in
|
|
87
|
+
`managedRuntime.variants` and select it with
|
|
88
|
+
`devrouter ensure . --variant <name>`. A profile continues to select resources;
|
|
89
|
+
the variant changes the managed process startup input. Declared
|
|
90
|
+
loopback-only service ports are available through `devrouter env . --json`. See
|
|
91
|
+
the [managed devcontainer contract](./docs/DEVCONTAINER.md) for ownership,
|
|
92
|
+
Compose, recovery, and capacity rules.
|
|
93
|
+
|
|
85
94
|
Automation can inspect the same profile contract without touching a workspace,
|
|
86
95
|
Docker, DevPod, Devsy, Traefik, Git, or global state:
|
|
87
96
|
|
|
@@ -145,7 +154,9 @@ explicit `--write-agents` or `--write-skill` flags.
|
|
|
145
154
|
- [Domain context](./CONTEXT.md) — shared vocabulary consumed by Matt Pocock planning skills.
|
|
146
155
|
- [Contributor guide](./AGENTS.md) — source map, invariants, validation, and release checklist.
|
|
147
156
|
- [Examples](./examples/routing/README.md) — routing without a devcontainer; see also the [managed DevPod example](./examples/devcontainer/README.md) and [parallel workspace example](./examples/workspace/README.md).
|
|
148
|
-
- [Project records](./docs/project/
|
|
157
|
+
- [Project records](./docs/project/) — dated plans and roadmap state.
|
|
149
158
|
- [Release history](./CHANGELOG.md) and [adaptation prompts](./upgrade-prompts/) — versioned change guidance.
|
|
150
159
|
|
|
151
160
|
Run `devrouter --help` for the complete current command and option reference.
|
|
161
|
+
|
|
162
|
+
Remote review environments use opt-in [planning and reviewed installation commands](docs/PREVIEWS.md).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Devrouter installation sweep
|
|
2
|
+
on:
|
|
3
|
+
schedule:
|
|
4
|
+
- cron: '*/5 * * * *'
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
id-token: write
|
|
9
|
+
jobs:
|
|
10
|
+
sweep:
|
|
11
|
+
if: github.event_name == 'schedule' || github.ref_name == github.event.repository.default_branch
|
|
12
|
+
uses: rschlaefli/devrouter/.github/workflows/preview.yml@__CONTROLLER_REF__
|
|
13
|
+
with:
|
|
14
|
+
controller-ref: __CONTROLLER_REF__
|
|
15
|
+
policy-repository: __POLICY_REPOSITORY__
|
|
16
|
+
policy-ref: __POLICY_REF__
|
|
17
|
+
installation: __INSTALLATION__
|
|
18
|
+
mode: sweep
|
|
19
|
+
azure-client-id: ${{ vars.DEVROUTER_PREVIEW_AZURE_CLIENT_ID }}
|
|
20
|
+
azure-tenant-id: ${{ vars.DEVROUTER_PREVIEW_AZURE_TENANT_ID }}
|
|
21
|
+
secrets:
|
|
22
|
+
policy-read-token: ${{ secrets.DEVROUTER_PREVIEW_POLICY_READ_TOKEN }}
|
|
23
|
+
credentials: ${{ secrets.DEVROUTER_PREVIEW_CREDENTIALS }}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Devrouter previews
|
|
2
|
+
on:
|
|
3
|
+
issue_comment:
|
|
4
|
+
types: [created]
|
|
5
|
+
pull_request_target:
|
|
6
|
+
types: [closed, synchronize, reopened]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
change:
|
|
10
|
+
description: PR number
|
|
11
|
+
type: string
|
|
12
|
+
required: true
|
|
13
|
+
# Install a separate central caller with mode=sweep and a */5 schedule once per installation.
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
id-token: write
|
|
17
|
+
jobs:
|
|
18
|
+
preview:
|
|
19
|
+
if: >-
|
|
20
|
+
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/preview ')) ||
|
|
21
|
+
github.event_name == 'pull_request_target' ||
|
|
22
|
+
(github.event_name == 'workflow_dispatch' && github.ref_name == github.event.repository.default_branch)
|
|
23
|
+
uses: rschlaefli/devrouter/.github/workflows/preview.yml@__CONTROLLER_REF__
|
|
24
|
+
with:
|
|
25
|
+
controller-ref: __CONTROLLER_REF__
|
|
26
|
+
policy-repository: __POLICY_REPOSITORY__
|
|
27
|
+
policy-ref: __POLICY_REF__
|
|
28
|
+
installation: __INSTALLATION__
|
|
29
|
+
project: __PROJECT__
|
|
30
|
+
change: ${{ format('{0}', github.event.issue.number || github.event.pull_request.number || inputs.change) }}
|
|
31
|
+
azure-client-id: ${{ vars.DEVROUTER_PREVIEW_AZURE_CLIENT_ID }}
|
|
32
|
+
azure-tenant-id: ${{ vars.DEVROUTER_PREVIEW_AZURE_TENANT_ID }}
|
|
33
|
+
secrets:
|
|
34
|
+
policy-read-token: ${{ secrets.DEVROUTER_PREVIEW_POLICY_READ_TOKEN }}
|
|
35
|
+
credentials: ${{ secrets.DEVROUTER_PREVIEW_CREDENTIALS }}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Before activation, set controller project pipeline-variable overrides to no_one_allowed.
|
|
2
|
+
# A trusted controller project vendors or immutably includes this template.
|
|
3
|
+
spec:
|
|
4
|
+
inputs:
|
|
5
|
+
controller_image:
|
|
6
|
+
regex: '^[A-Za-z0-9][A-Za-z0-9._:/-]*@sha256:[a-f0-9]{64}$'
|
|
7
|
+
preview_mode:
|
|
8
|
+
default: sweep
|
|
9
|
+
options: [handle-event, sweep]
|
|
10
|
+
preview_project:
|
|
11
|
+
default: ''
|
|
12
|
+
regex: '^[a-z0-9-]*$'
|
|
13
|
+
preview_change:
|
|
14
|
+
default: ''
|
|
15
|
+
regex: '^[0-9]*$'
|
|
16
|
+
---
|
|
17
|
+
devrouter:preview:
|
|
18
|
+
image: $[[ inputs.controller_image ]]
|
|
19
|
+
stage: deploy
|
|
20
|
+
timeout: 18m
|
|
21
|
+
variables:
|
|
22
|
+
GIT_STRATEGY: none
|
|
23
|
+
id_tokens:
|
|
24
|
+
DEVROUTER_PREVIEW_AZURE_ASSERTION:
|
|
25
|
+
aud: api://AzureADTokenExchange
|
|
26
|
+
rules:
|
|
27
|
+
- if: '$CI_COMMIT_REF_PROTECTED == "true" && ($CI_PIPELINE_SOURCE == "trigger" || $CI_PIPELINE_SOURCE == "schedule")'
|
|
28
|
+
- when: never
|
|
29
|
+
script:
|
|
30
|
+
- >-
|
|
31
|
+
node /opt/devrouter/dist/devrouter.js preview '$[[ inputs.preview_mode ]]'
|
|
32
|
+
--installation /opt/devrouter-policy/installation.json
|
|
33
|
+
--project '$[[ inputs.preview_project ]]'
|
|
34
|
+
--change '$[[ inputs.preview_change ]]' --json
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Install in a trusted controller project, outside candidate branch pipelines.
|
|
2
|
+
spec:
|
|
3
|
+
inputs:
|
|
4
|
+
preview_mode:
|
|
5
|
+
default: sweep
|
|
6
|
+
options: [handle-event, sweep]
|
|
7
|
+
preview_project:
|
|
8
|
+
default: ''
|
|
9
|
+
regex: '^[a-z0-9-]*$'
|
|
10
|
+
preview_change:
|
|
11
|
+
default: ''
|
|
12
|
+
regex: '^[0-9]*$'
|
|
13
|
+
---
|
|
14
|
+
stages: [deploy]
|
|
15
|
+
include:
|
|
16
|
+
- remote: https://raw.githubusercontent.com/rschlaefli/devrouter/__CONTROLLER_REF__/assets/preview/gitlab-template.yml
|
|
17
|
+
integrity: __TEMPLATE_INTEGRITY__
|
|
18
|
+
inputs:
|
|
19
|
+
controller_image: __CONTROLLER_IMAGE__
|
|
20
|
+
preview_mode: $[[ inputs.preview_mode ]]
|
|
21
|
+
preview_project: $[[ inputs.preview_project ]]
|
|
22
|
+
preview_change: $[[ inputs.preview_change ]]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"installationId": "example",
|
|
4
|
+
"state": {
|
|
5
|
+
"containerUrl": "https://examplestore.blob.core.windows.net/previews",
|
|
6
|
+
"tokenEnv": "DEVROUTER_PREVIEW_STATE_TOKEN"
|
|
7
|
+
},
|
|
8
|
+
"maxActive": 2,
|
|
9
|
+
"maxReservedCents": 500,
|
|
10
|
+
"projects": [
|
|
11
|
+
{
|
|
12
|
+
"key": "web",
|
|
13
|
+
"forge": {
|
|
14
|
+
"kind": "github",
|
|
15
|
+
"host": "github.com",
|
|
16
|
+
"apiUrl": "https://api.github.com/",
|
|
17
|
+
"repository": "example/app",
|
|
18
|
+
"projectId": "1",
|
|
19
|
+
"botId": "2",
|
|
20
|
+
"tokenEnv": "DEVROUTER_PREVIEW_GITHUB_TOKEN"
|
|
21
|
+
},
|
|
22
|
+
"config": { "file": "app/.devrouter.yml", "sha256": "REPLACE_WITH_REVIEWED_FILE_SHA256" },
|
|
23
|
+
"manifest": {
|
|
24
|
+
"file": "app/.devrouter.preview.yml",
|
|
25
|
+
"sha256": "REPLACE_WITH_REVIEWED_FILE_SHA256"
|
|
26
|
+
},
|
|
27
|
+
"northflank": {
|
|
28
|
+
"projectId": "example-previews",
|
|
29
|
+
"tokenEnv": "DEVROUTER_PREVIEW_NORTHFLANK_TOKEN",
|
|
30
|
+
"graph": {
|
|
31
|
+
"namespace": "example",
|
|
32
|
+
"baseDomain": "preview.example.org",
|
|
33
|
+
"allowedNetworks": ["192.0.2.0/24"],
|
|
34
|
+
"resources": {
|
|
35
|
+
"web": {
|
|
36
|
+
"deploymentPlan": "nf-compute-10",
|
|
37
|
+
"readiness": { "port": "http", "path": "/health" }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"qualification": {
|
|
42
|
+
"fixedDeadline": false,
|
|
43
|
+
"sameEnvironment": false,
|
|
44
|
+
"deletionFence": false,
|
|
45
|
+
"scopedRuntimeSecrets": false,
|
|
46
|
+
"restrictedIngress": false
|
|
47
|
+
},
|
|
48
|
+
"runtimeSecrets": {}
|
|
49
|
+
},
|
|
50
|
+
"hourlyCents": { "web": 1 },
|
|
51
|
+
"acceptance": { "command": ["/bin/false"], "environment": [] }
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
package/bin/devrouter-process
CHANGED
|
@@ -9,8 +9,9 @@ Usage:
|
|
|
9
9
|
devrouter-process status --name <name>
|
|
10
10
|
|
|
11
11
|
Options:
|
|
12
|
-
--fingerprint <value> Runtime identity. Defaults to command, workspace, adapter,
|
|
13
|
-
|
|
12
|
+
--fingerprint <value> Runtime identity. Defaults to command, workspace, adapter, non-default
|
|
13
|
+
managed variant, and safe allowlisted environment identity.
|
|
14
|
+
An explicit fingerprint remains caller-owned for preparation identity.
|
|
14
15
|
--prepare-command <shell command>
|
|
15
16
|
Ensure only: run a nonempty command with bash before a changed/new runtime.
|
|
16
17
|
Included byte-for-byte in the default fingerprint; skipped on runtime reuse.
|
|
@@ -22,6 +23,7 @@ Options:
|
|
|
22
23
|
Environment:
|
|
23
24
|
DEVROUTER_PROCESS_ADAPTER_SHA256 Exact managed-adapter SHA-256 supplied by devrouter.
|
|
24
25
|
DEVROUTER_PROCESS_FINGERPRINT_ENV Comma-separated non-secret environment names to fingerprint.
|
|
26
|
+
DEVROUTER_RUNTIME_VARIANT Managed runtime variant; defaults to 'default'. Non-default values are part of identity.
|
|
25
27
|
EOF
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -141,6 +143,18 @@ if [[ -v DEVROUTER_PROCESS_ADAPTER_SHA256 ]] &&
|
|
|
141
143
|
die "DEVROUTER_PROCESS_ADAPTER_SHA256 must be a SHA-256 digest."
|
|
142
144
|
fi
|
|
143
145
|
|
|
146
|
+
runtime_variant="${DEVROUTER_RUNTIME_VARIANT-default}"
|
|
147
|
+
if [ "${#runtime_variant}" -gt 64 ] ||
|
|
148
|
+
! [[ "$runtime_variant" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
|
149
|
+
die "DEVROUTER_RUNTIME_VARIANT must use lowercase alphanumeric segments separated by hyphens and be at most 64 characters."
|
|
150
|
+
fi
|
|
151
|
+
managed_variant_identity=0
|
|
152
|
+
[ "$runtime_variant" = "default" ] || managed_variant_identity=1
|
|
153
|
+
host_ports_identity="${DEVROUTER_PROCESS_HOST_PORTS_SHA256:-}"
|
|
154
|
+
if [ -n "$host_ports_identity" ] && ! [[ "$host_ports_identity" =~ ^[a-f0-9]{64}$ ]]; then
|
|
155
|
+
die "DEVROUTER_PROCESS_HOST_PORTS_SHA256 must be a SHA-256 digest."
|
|
156
|
+
fi
|
|
157
|
+
|
|
144
158
|
if [ "$action" != "ensure" ] && [ "$#" -gt 0 ]; then
|
|
145
159
|
die "Unexpected arguments for $action."
|
|
146
160
|
fi
|
|
@@ -163,6 +177,12 @@ if [ -z "$fingerprint" ]; then
|
|
|
163
177
|
emit_environment_field workspace WORKSPACE
|
|
164
178
|
emit_environment_field devrouter-workspace DEVROUTER_WORKSPACE
|
|
165
179
|
emit_environment_field adapter-sha256 DEVROUTER_PROCESS_ADAPTER_SHA256
|
|
180
|
+
if [ "$managed_variant_identity" -eq 1 ]; then
|
|
181
|
+
printf 'runtime-variant\0%s\0' "$runtime_variant"
|
|
182
|
+
fi
|
|
183
|
+
if [ -n "$host_ports_identity" ]; then
|
|
184
|
+
printf 'host-ports\0%s\0' "$host_ports_identity"
|
|
185
|
+
fi
|
|
166
186
|
for argument in "$@"; do
|
|
167
187
|
printf 'argv\0%s\0' "$argument"
|
|
168
188
|
done
|
|
@@ -174,6 +194,13 @@ if [ -z "$fingerprint" ]; then
|
|
|
174
194
|
emit_environment_field environment-value "$env_name"
|
|
175
195
|
done
|
|
176
196
|
} | LC_ALL=C sha256sum | awk '{print $1}')"
|
|
197
|
+
elif [ "$managed_variant_identity" -eq 1 ] || [ -n "$host_ports_identity" ]; then
|
|
198
|
+
fingerprint="$({
|
|
199
|
+
printf 'format\0devrouter-process-managed-variant-v1\0'
|
|
200
|
+
printf 'explicit-fingerprint\0%s\0' "$fingerprint"
|
|
201
|
+
printf 'runtime-variant\0%s\0' "$runtime_variant"
|
|
202
|
+
printf 'host-ports\0%s\0' "$host_ports_identity"
|
|
203
|
+
} | LC_ALL=C sha256sum | awk '{print $1}')"
|
|
177
204
|
fi
|
|
178
205
|
[[ "$fingerprint" =~ ^[a-zA-Z0-9][a-zA-Z0-9._:-]*$ ]] || die "--fingerprint must be a safe identifier."
|
|
179
206
|
|