@monster-orange/den 0.0.0 → 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/CHANGELOG.md +204 -0
- package/LICENSE +21 -0
- package/README.md +165 -1
- package/bin/den +68 -0
- package/docs/distributions.md +499 -0
- package/make/demo.mk +82 -0
- package/make/den.mk +80 -0
- package/make/journeys.mk +57 -0
- package/make/local_dev.mk +154 -0
- package/make/security.mk +59 -0
- package/make/test.mk +405 -0
- package/package.json +101 -4
- package/scripts/auth-configure.ts +415 -0
- package/scripts/heal-config.ts +92 -0
- package/scripts/jsonl-playwright-reporter.js +70 -0
- package/scripts/manifest-read.cjs +91 -0
- package/scripts/setup-1password.ts +570 -0
- package/scripts/setup-secrets.ts +149 -0
- package/scripts/view-results.js +156 -0
- package/service/install.sh +112 -0
- package/src/pillars/api/fixtures/index.ts +128 -0
- package/src/pillars/api/fixtures/openapi-validator.ts +111 -0
- package/src/pillars/api/global-setup.ts +103 -0
- package/src/pillars/api/playwright.config.ts +105 -0
- package/src/pillars/api/schemas/example-api.json +110 -0
- package/src/pillars/api/tests/health/health.spec.ts +19 -0
- package/src/pillars/api/tests/health/manifest.yml +6 -0
- package/src/pillars/browser/fixtures/index.ts +232 -0
- package/src/pillars/browser/fixtures/package.json +10 -0
- package/src/pillars/browser/global-setup.ts +140 -0
- package/src/pillars/browser/global-teardown.ts +48 -0
- package/src/pillars/browser/playwright.config.ts +212 -0
- package/src/pillars/browser/setup.ts +219 -0
- package/src/pillars/journeys/app-config.ts +237 -0
- package/src/pillars/journeys/discover.ts +160 -0
- package/src/pillars/journeys/hooks/deny-shell.cjs +44 -0
- package/src/pillars/journeys/observability/events.ts +288 -0
- package/src/pillars/journeys/observability/sdk-mapper.ts +306 -0
- package/src/pillars/journeys/report/friction.ts +304 -0
- package/src/pillars/journeys/report/junit.ts +105 -0
- package/src/pillars/journeys/report/render.ts +273 -0
- package/src/pillars/journeys/report/results.ts +323 -0
- package/src/pillars/journeys/run.ts +673 -0
- package/src/pillars/journeys/runner.ts +1025 -0
- package/src/pillars/journeys/sandbox.ts +403 -0
- package/src/pillars/journeys/spec/loader.ts +152 -0
- package/src/pillars/journeys/spec/schema.ts +208 -0
- package/src/pillars/journeys/teardown.ts +98 -0
- package/src/pillars/journeys/tools/browser-session.ts +219 -0
- package/src/pillars/journeys/tools/browser-tool.ts +914 -0
- package/src/pillars/journeys/tools/http-tool.ts +564 -0
- package/src/pillars/journeys/tools/ledger.ts +278 -0
- package/src/pillars/journeys/tools/snapshot-store.ts +117 -0
- package/src/pillars/journeys/verify/assertions.ts +502 -0
- package/src/pillars/journeys/verify/verdict.ts +71 -0
- package/src/pillars/perf/build-report.ts +36 -0
- package/src/pillars/perf/k6.config.js +112 -0
- package/src/pillars/perf/run.ts +345 -0
- package/src/pillars/perf/scenarios/load-profile.js +97 -0
- package/src/pillars/perf/staging.ts +73 -0
- package/src/pillars/security/discover.ts +124 -0
- package/src/pillars/security/findings.ts +151 -0
- package/src/pillars/security/plan.ts +355 -0
- package/src/pillars/security/run.ts +757 -0
- package/src/pillars/smoke/admin-probe.ts +68 -0
- package/src/pillars/smoke/base-url.ts +56 -0
- package/src/pillars/smoke/cleanup.ts +8 -0
- package/src/pillars/smoke/discover.ts +237 -0
- package/src/pillars/smoke/ensure-smoke-teardown.ts +40 -0
- package/src/pillars/smoke/fixture-manager.ts +217 -0
- package/src/pillars/smoke/fixtures.ts +468 -0
- package/src/pillars/smoke/global-setup-all.ts +262 -0
- package/src/pillars/smoke/global-setup-global.ts +262 -0
- package/src/pillars/smoke/global-setup.ts +273 -0
- package/src/pillars/smoke/global-teardown-all.ts +8 -0
- package/src/pillars/smoke/global-teardown-global.ts +8 -0
- package/src/pillars/smoke/global-teardown.ts +139 -0
- package/src/pillars/smoke/playwright-all.config.ts +147 -0
- package/src/pillars/smoke/playwright-global.config.ts +141 -0
- package/src/pillars/smoke/playwright.config.ts +162 -0
- package/src/pillars/smoke/setup-env.ts +132 -0
- package/src/pillars/smoke/setup-global.ts +126 -0
- package/src/pillars/smoke/setup.ts +115 -0
- package/src/pillars/smoke/smoke-repo.ts +16 -0
- package/src/pillars/smoke/staging.ts +49 -0
- package/src/pillars/suites/run.ts +147 -0
- package/src/scripts/configure-aws-profiles.ts +114 -0
- package/src/scripts/register-repos.ts +307 -0
- package/src/scripts/setup-default-workspace.ts +203 -0
- package/src/shared/agent-actor.ts +77 -0
- package/src/shared/applications.ts +138 -0
- package/src/shared/auth/api-token.ts +416 -0
- package/src/shared/auth/auth0-helper.ts +284 -0
- package/src/shared/auth/headless-login.ts +265 -0
- package/src/shared/auth/jwt-helper.ts +186 -0
- package/src/shared/auth/sudo-vault.ts +69 -0
- package/src/shared/auth/test-accounts.ts +98 -0
- package/src/shared/auth/token-injection.ts +184 -0
- package/src/shared/auth/token-providers/auth0.ts +80 -0
- package/src/shared/auth/token-providers/index.ts +182 -0
- package/src/shared/auth/token-refresh.ts +273 -0
- package/src/shared/banner.ts +15 -0
- package/src/shared/brand.ts +79 -0
- package/src/shared/cli-tabs.ts +131 -0
- package/src/shared/constants.ts +128 -0
- package/src/shared/den-config.ts +688 -0
- package/src/shared/dev-metrics/emit.ts +354 -0
- package/src/shared/edge/config.ts +229 -0
- package/src/shared/edge/render.ts +221 -0
- package/src/shared/edge/runtime.ts +268 -0
- package/src/shared/edge/status.ts +74 -0
- package/src/shared/edge/types.ts +62 -0
- package/src/shared/engine.ts +67 -0
- package/src/shared/environment/aws-profiles.ts +49 -0
- package/src/shared/environment/env-selector.ts +161 -0
- package/src/shared/environment/playwright-env.ts +82 -0
- package/src/shared/environment-manager/catalog.ts +77 -0
- package/src/shared/environment-manager/clone-guard.ts +163 -0
- package/src/shared/environment-manager/dag.ts +286 -0
- package/src/shared/environment-manager/default-workspace.ts +182 -0
- package/src/shared/environment-manager/derivation/alias.ts +90 -0
- package/src/shared/environment-manager/derivation/cache.ts +97 -0
- package/src/shared/environment-manager/derivation/derive-graph.ts +421 -0
- package/src/shared/environment-manager/derivation/derived-up.ts +354 -0
- package/src/shared/environment-manager/derivation/load-alias.ts +11 -0
- package/src/shared/environment-manager/derivation/rules-compose.ts +42 -0
- package/src/shared/environment-manager/derivation/rules-events.ts +50 -0
- package/src/shared/environment-manager/derivation/rules-http.ts +247 -0
- package/src/shared/environment-manager/derivation/rules-infra.ts +64 -0
- package/src/shared/environment-manager/derivation/rules-readiness.ts +96 -0
- package/src/shared/environment-manager/derivation/scan.ts +160 -0
- package/src/shared/environment-manager/derivation/text.ts +40 -0
- package/src/shared/environment-manager/derivation/types.ts +69 -0
- package/src/shared/environment-manager/health.ts +635 -0
- package/src/shared/environment-manager/index.ts +6 -0
- package/src/shared/environment-manager/load-applications.ts +108 -0
- package/src/shared/environment-manager/log-tail.ts +213 -0
- package/src/shared/environment-manager/make-targets.ts +78 -0
- package/src/shared/environment-manager/opctl.ts +335 -0
- package/src/shared/environment-manager/readiness.ts +93 -0
- package/src/shared/environment-manager/register-local.ts +72 -0
- package/src/shared/environment-manager/secrets-check.ts +260 -0
- package/src/shared/environment-manager/service-container.ts +47 -0
- package/src/shared/environment-manager/service-env.ts +110 -0
- package/src/shared/environment-manager/service-runner.ts +1603 -0
- package/src/shared/environment-manager/sync-targets.ts +66 -0
- package/src/shared/environment-manager/up-plan.ts +326 -0
- package/src/shared/environment-manager/workspace-manager.ts +905 -0
- package/src/shared/environment-manager/workspaces.ts +860 -0
- package/src/shared/manifest/deps.ts +27 -0
- package/src/shared/manifest/merge-override.ts +75 -0
- package/src/shared/manifest/migrate-manifest.ts +101 -0
- package/src/shared/manifest/placement.ts +321 -0
- package/src/shared/manifest/read-manifest.ts +278 -0
- package/src/shared/manifest/schema.ts +313 -0
- package/src/shared/manifest/service-links.ts +93 -0
- package/src/shared/manifest/validate-layers.ts +229 -0
- package/src/shared/manifest/validate-manifest.ts +200 -0
- package/src/shared/manifest/workspace-manifests.ts +92 -0
- package/src/shared/open-url.ts +122 -0
- package/src/shared/org.ts +44 -0
- package/src/shared/paths.ts +190 -0
- package/src/shared/perf/optional-fields.ts +105 -0
- package/src/shared/perf/report-normalizer.ts +404 -0
- package/src/shared/perf/report-paths.ts +19 -0
- package/src/shared/perf/report-store.ts +110 -0
- package/src/shared/perf/report-types.ts +70 -0
- package/src/shared/perf/test-paths.ts +25 -0
- package/src/shared/process/log-rotation.ts +147 -0
- package/src/shared/process/spawn-streaming.ts +229 -0
- package/src/shared/product.ts +92 -0
- package/src/shared/profile.ts +141 -0
- package/src/shared/redact.ts +107 -0
- package/src/shared/repo-kind.ts +32 -0
- package/src/shared/reporting/jsonl-reporter.ts +131 -0
- package/src/shared/reporting/slack-reporter.ts +340 -0
- package/src/shared/results/result-reader.ts +266 -0
- package/src/shared/results/result-writer.ts +168 -0
- package/src/shared/secrets/doppler.ts +126 -0
- package/src/shared/secrets/env.ts +48 -0
- package/src/shared/secrets/index.ts +197 -0
- package/src/shared/secrets/keys.ts +33 -0
- package/src/shared/secrets/onepassword.ts +75 -0
- package/src/shared/secrets/types.ts +52 -0
- package/src/shared/service-url.ts +119 -0
- package/src/shared/smoke/branch-resolver.ts +141 -0
- package/src/shared/smoke/git-remote.ts +70 -0
- package/src/shared/smoke/repo-cloner.ts +151 -0
- package/src/shared/stacks/config.ts +137 -0
- package/src/shared/stacks/manifest-commands.ts +118 -0
- package/src/shared/stacks/render.ts +253 -0
- package/src/shared/stacks/runtime.ts +334 -0
- package/src/shared/stacks/status.ts +99 -0
- package/src/shared/stacks/types.ts +53 -0
- package/src/shared/terminal/tabs.ts +212 -0
- package/src/shared/test-discovery/module-scanner.ts +569 -0
- package/src/shared/types/index.ts +701 -0
- package/src/shared/ui-marker.ts +19 -0
- package/src/ui/cli/applications-command.ts +148 -0
- package/src/ui/cli/config-command.ts +68 -0
- package/src/ui/cli/create-main.ts +9 -0
- package/src/ui/cli/create.ts +360 -0
- package/src/ui/cli/edge-command.ts +81 -0
- package/src/ui/cli/flag-parser.ts +246 -0
- package/src/ui/cli/graph-command.ts +570 -0
- package/src/ui/cli/health-display.ts +63 -0
- package/src/ui/cli/index.ts +3742 -0
- package/src/ui/cli/init.ts +855 -0
- package/src/ui/cli/invocation-target.ts +175 -0
- package/src/ui/cli/logs-command.ts +104 -0
- package/src/ui/cli/mcp-main.ts +13 -0
- package/src/ui/cli/mcp-stdout-guard.ts +10 -0
- package/src/ui/cli/module-selection.ts +31 -0
- package/src/ui/cli/prompts.ts +767 -0
- package/src/ui/cli/results-viewer.ts +436 -0
- package/src/ui/cli/secrets-preflight.ts +91 -0
- package/src/ui/cli/stack-command.ts +117 -0
- package/src/ui/cli/stalled-setup-recovery.ts +129 -0
- package/src/ui/cli/test-runner.ts +1319 -0
- package/src/ui/cli/web-command.ts +1073 -0
- package/src/ui/mcp/api.ts +284 -0
- package/src/ui/mcp/guards.ts +141 -0
- package/src/ui/mcp/server.ts +147 -0
- package/src/ui/mcp/tools.ts +565 -0
- package/src/ui/server/audit.ts +71 -0
- package/src/ui/server/changelog-parser.ts +105 -0
- package/src/ui/server/daemon-reaper.ts +129 -0
- package/src/ui/server/editor-manager.ts +301 -0
- package/src/ui/server/github-service.ts +223 -0
- package/src/ui/server/graph-prefs.ts +89 -0
- package/src/ui/server/health-row.ts +15 -0
- package/src/ui/server/http-helpers.ts +98 -0
- package/src/ui/server/index.ts +3350 -0
- package/src/ui/server/log-history.ts +453 -0
- package/src/ui/server/perf-report.ts +42 -0
- package/src/ui/server/public/environments.html +496 -0
- package/src/ui/server/public/favicon.ico +0 -0
- package/src/ui/server/public/graph-model.js +416 -0
- package/src/ui/server/public/graph.css +976 -0
- package/src/ui/server/public/graph.js +986 -0
- package/src/ui/server/public/header.js +1373 -0
- package/src/ui/server/public/index.html +2595 -0
- package/src/ui/server/public/local-dev.html +5344 -0
- package/src/ui/server/public/logs.html +1496 -0
- package/src/ui/server/public/panel.js +787 -0
- package/src/ui/server/public/perf-report.js +359 -0
- package/src/ui/server/public/release.html +2111 -0
- package/src/ui/server/public/services.html +1103 -0
- package/src/ui/server/public/workspace-picker.js +69 -0
- package/src/ui/server/readonly-routes.ts +200 -0
- package/src/ui/server/release-deploy-session.ts +246 -0
- package/src/ui/server/release-service.ts +1125 -0
- package/src/ui/server/sudo-store.ts +111 -0
- package/src/ui/server/ui-assets.ts +73 -0
- package/src/ui/server/workspace-routes.ts +2185 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# Distributions
|
|
2
|
+
|
|
3
|
+
Den is one engine, `@monster-orange/den`. You run it through a small repo of
|
|
4
|
+
your own, a **distribution**, that installs Den as a package and holds
|
|
5
|
+
everything that makes it yours: its name, brand, config, manifests and tests.
|
|
6
|
+
Den's own checkout is itself a distribution, named `den`.
|
|
7
|
+
|
|
8
|
+
- [Create one](#create-one)
|
|
9
|
+
- [Layout](#layout)
|
|
10
|
+
- [den.yml: the product profile](#denyml-the-product-profile)
|
|
11
|
+
- [Brand](#brand)
|
|
12
|
+
- [The bin shim](#the-bin-shim)
|
|
13
|
+
- [make: den.mk](#make-denmk)
|
|
14
|
+
- [Two roots](#two-roots)
|
|
15
|
+
- [Pinning and upgrading](#pinning-and-upgrading)
|
|
16
|
+
- [Developing Den against a distribution](#developing-den-against-a-distribution)
|
|
17
|
+
|
|
18
|
+
## Create one
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npx @monster-orange/den create acme # writes ./acme
|
|
22
|
+
npx @monster-orange/den create acme ~/src/acme-dev --title "Acme Dev"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
From a Den checkout, `./bin/den create acme ../acme` does the same.
|
|
26
|
+
|
|
27
|
+
| Option | Default | What |
|
|
28
|
+
| ----------------------- | ------------------- | ------------------------------------- |
|
|
29
|
+
| `<name>` | (required) | Product name: `[a-z][a-z0-9-]*` |
|
|
30
|
+
| `[dir]` | `./<name>` | A new or empty directory |
|
|
31
|
+
| `--title <title>` | `<Name>` Title Case | Brand name shown to people |
|
|
32
|
+
| `--cli <cli>` | `<name>` | The command people type |
|
|
33
|
+
| `--env-prefix <PREFIX>` | `<NAME>` | Env-var prefix (`ACME` → `ACME_HOME`) |
|
|
34
|
+
|
|
35
|
+
`create` refuses a directory that is not empty and never overwrites a file.
|
|
36
|
+
[`examples/distribution/`](../examples/distribution) is exactly the output of
|
|
37
|
+
`den create acme`; a unit test regenerates it, so the two never drift
|
|
38
|
+
(`npm run example:regen` after changing the scaffolder).
|
|
39
|
+
|
|
40
|
+
Then:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
cd acme
|
|
44
|
+
npm install
|
|
45
|
+
./bin/acme --help
|
|
46
|
+
./bin/acme web # the web UI, branded "Acme"
|
|
47
|
+
make help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Layout
|
|
51
|
+
|
|
52
|
+
| Path | What |
|
|
53
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
54
|
+
| `den.yml` | The product profile ([below](#denyml-the-product-profile)) |
|
|
55
|
+
| `package.json` | Pins an exact `@monster-orange/den` version |
|
|
56
|
+
| `bin/<cli>` | The shim people run ([below](#the-bin-shim)) |
|
|
57
|
+
| `Makefile` | Includes Den's targets ([below](#make-denmk)) |
|
|
58
|
+
| `config/<name>.yml` | Org config: brand, `github_org`, `secrets`, `edge`, … |
|
|
59
|
+
| `config/environments/` | One `<env>.json` per environment (base URLs, auth, timeouts) |
|
|
60
|
+
| `config/local/` | Per-engineer overrides (`user.yml`); gitignored |
|
|
61
|
+
| `manifests/` | Manifests for repos that do not carry their own, and overrides ([below](#overriding-a-manifest)) |
|
|
62
|
+
| `tests/pillars/<pillar>/` | Your own suites, e.g. `tests/pillars/perf/<module>/test.js` |
|
|
63
|
+
| `reports/`, `results/` | Test output; gitignored |
|
|
64
|
+
|
|
65
|
+
## Overriding a manifest
|
|
66
|
+
|
|
67
|
+
A repo's manifest comes from one base: the repo's own file (`.acme.yml`, or
|
|
68
|
+
its `.json` twin) or, when the repo has none, the one the distribution holds
|
|
69
|
+
at `manifests/<repo>.acme.yml`. On top of that base, an optional
|
|
70
|
+
`manifests/<repo>.override.yml` changes what this distribution needs to
|
|
71
|
+
differ, without a commit to the repo. The override file is named with
|
|
72
|
+
`.override` plus the manifest's extension, and `<repo>` is matched exactly as
|
|
73
|
+
for a held manifest: the checkout's `origin` repo name, then the managed-clone
|
|
74
|
+
name, then the folder name.
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
# manifests/shop.override.yml, merged onto shop's own .acme.yml
|
|
78
|
+
services:
|
|
79
|
+
web:
|
|
80
|
+
commands:
|
|
81
|
+
local:
|
|
82
|
+
up: make up-fast # replaces up; the base's other commands stay
|
|
83
|
+
depends_on: [] # lists replace whole: web no longer waits on api
|
|
84
|
+
urls: null # null deletes the key
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Merge rules:
|
|
88
|
+
|
|
89
|
+
- Maps merge by key, recursively.
|
|
90
|
+
- Lists and scalars replace the base value whole.
|
|
91
|
+
- An explicit `null` deletes the key from the result.
|
|
92
|
+
|
|
93
|
+
An override only changes or deletes what the base has. A service or key the
|
|
94
|
+
base lacks is an error, even inside a map whose keys are free-form (a new
|
|
95
|
+
command, a new environment): put new entries in the base. An override with no
|
|
96
|
+
base is an error, never a manifest on its own.
|
|
97
|
+
|
|
98
|
+
`<cli> validate <repo-dir>` checks each layer against the schema on its own,
|
|
99
|
+
naming the file each error is in, then checks the merged result:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
✓ /src/shop/.acme.yml (repo, v1, no issues)
|
|
103
|
+
✗ /dist/manifests/shop.override.yml (override, v1, 1 error)
|
|
104
|
+
ERROR services.api.commands.local.down unknown key "down": not in the base manifest
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The web UI's Services cards show the layers each manifest was built from
|
|
108
|
+
(`manifest: repo + override`), and `/api/services` returns them per service as
|
|
109
|
+
`manifestLayers`, e.g. `["held", "override"]`. `DEN_MANIFESTS_DIR` points the
|
|
110
|
+
held and override lookup at another directory (tests use it).
|
|
111
|
+
|
|
112
|
+
## Placement
|
|
113
|
+
|
|
114
|
+
Each service says where it runs, per environment: `local` (on this machine,
|
|
115
|
+
started by Den) or `remote` (deployed elsewhere). A remote service still
|
|
116
|
+
shows in the graph, the health row and the applications, marked ☁, but Den
|
|
117
|
+
never starts, stops, scans or execs it. The common case is a hybrid
|
|
118
|
+
application: its frontend runs here and calls the team's dev deployment of
|
|
119
|
+
its backend.
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
# .acme.yml of shop-core
|
|
123
|
+
services:
|
|
124
|
+
core:
|
|
125
|
+
runs: { local: remote, dev: remote } # per env: local | remote
|
|
126
|
+
target:
|
|
127
|
+
env: dev # one of the org's environments
|
|
128
|
+
account: AWS # a label for where it is deployed
|
|
129
|
+
url: https://api.dev.acme.example/admin/manifest
|
|
130
|
+
expect: 401 # the API answers 401 when it is up (behind a JWT authorizer)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When `runs` says nothing for the env being viewed:
|
|
134
|
+
|
|
135
|
+
- `local` if the service has commands there. Locally that also covers every
|
|
136
|
+
service of a repo that runs here: a compose stack, or a repo where any
|
|
137
|
+
service has `commands.local` (one repo-level `up` starts the others). A
|
|
138
|
+
remote service inside such a repo says `runs: { local: remote }`;
|
|
139
|
+
- `remote` if it has an HTTP health URL there and nothing in its repo runs
|
|
140
|
+
there;
|
|
141
|
+
- otherwise `none`: Den knows no runtime for it, and shows no placement.
|
|
142
|
+
|
|
143
|
+
`target` names where a remote service runs: `env`, an optional `account`
|
|
144
|
+
label, an optional `url`, and `expect`, a status code or a list of codes that
|
|
145
|
+
count as up when Den probes `url` (default: any 2xx). Codes are integers
|
|
146
|
+
100–599. A service with `runs.local: remote` must have a `target`.
|
|
147
|
+
|
|
148
|
+
**Health.** A remote service is checked by the health declared for its
|
|
149
|
+
`target.env` (`health.dev` above), the same check Den runs when you view that
|
|
150
|
+
env. Only when there is none does Den GET `target.url` and compare the status
|
|
151
|
+
with `expect`. The health row's label names the target, `dev · AWS`, followed
|
|
152
|
+
by the status or response time.
|
|
153
|
+
|
|
154
|
+
**Validation.** `<cli> validate` rejects an env name in `runs`, or a
|
|
155
|
+
`target.env`, that is not one of the org's `environments`, an unknown key in
|
|
156
|
+
`target`, and `expect` codes outside 100–599. Placement is the one thing an
|
|
157
|
+
[override](#overriding-a-manifest) may add to a service its base has, so a
|
|
158
|
+
distribution can place a repo's service remote without a commit to the repo:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
# manifests/shop-core.override.yml
|
|
162
|
+
services:
|
|
163
|
+
core:
|
|
164
|
+
runs: { local: remote }
|
|
165
|
+
target: { env: dev, account: AWS, url: https://api.dev.acme.example/health }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Where it shows.** `/api/services` and `/api/health` rows carry `runs`
|
|
169
|
+
(`local`, `remote` or `none`, for the env asked about) and `target`
|
|
170
|
+
(`{ env, account?, url? }`, or null unless remote). `/api/applications`
|
|
171
|
+
carries each service's placement in `placements` (keyed by address), and per
|
|
172
|
+
application `placement` (`local`, `remote`, `hybrid` or `none`) with a
|
|
173
|
+
`summary` such as `shop-frontend local · shop-core remote (dev)`.
|
|
174
|
+
`<cli> status` and `<cli> services` suffix remote services with
|
|
175
|
+
`☁ remote (dev)`; `<cli> apps` marks hybrid and remote applications and
|
|
176
|
+
repos; `<cli> graph` marks remote nodes (dashed in `--format dot`) and hybrid
|
|
177
|
+
ones (`⇄ hybrid`).
|
|
178
|
+
|
|
179
|
+
**Guards.**
|
|
180
|
+
|
|
181
|
+
- Service exec (`/api/service/exec`, `<cli> up|down|restart`, workspace-wide
|
|
182
|
+
up and down, `<cli> up`'s plan) refuses every command on a remote service:
|
|
183
|
+
`shop/core runs in dev (AWS); nothing to start here`. A `down` stops
|
|
184
|
+
nothing and succeeds, so a workspace down is not failed by it.
|
|
185
|
+
- MCP: `runsLocally()` reads the served `runs`, so agents cannot start, stop
|
|
186
|
+
or restart a remote service.
|
|
187
|
+
- Security: `auto_targets` never adds a remote service, even one with local
|
|
188
|
+
commands. A declared target of a remote service is not scanned in `local`,
|
|
189
|
+
only in other envs.
|
|
190
|
+
- **Production.** A remote service whose `target.env` counts as production is
|
|
191
|
+
never scanned, in any env, and never acted on. Production is an attribute of
|
|
192
|
+
an env in the org config, never a name check:
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
# config/acme.yml
|
|
196
|
+
production_envs: [prod] # default: [prod, production]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## den.yml: the product profile
|
|
200
|
+
|
|
201
|
+
Every runtime name derives from `product.name`. Set only what you want to
|
|
202
|
+
differ.
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
product:
|
|
206
|
+
name: acme
|
|
207
|
+
# cli: acme
|
|
208
|
+
# env_prefix: ACME
|
|
209
|
+
# config: config/acme.yml
|
|
210
|
+
# manifest: .acme.yml
|
|
211
|
+
# state_dir: ~/.acme
|
|
212
|
+
# services_dir: .acme-services
|
|
213
|
+
# workspaces_dir: acme-workspaces
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
| Field | Default | What it names |
|
|
217
|
+
| ---------------- | -------------------- | ----------------------------------------------------------------- |
|
|
218
|
+
| `name` | `den` | The product; `[a-z][a-z0-9-]*`. Everything below derives from it |
|
|
219
|
+
| `cli` | `<name>` | The command shown in help, hints and the web UI |
|
|
220
|
+
| `env_prefix` | `<NAME>` (`-` → `_`) | Env vars: `<PREFIX>_ROOT`, `<PREFIX>_HOME`, `<PREFIX>_INVOKE_CWD` |
|
|
221
|
+
| `config` | `config/<name>.yml` | The org config, relative to the distribution root |
|
|
222
|
+
| `manifest` | `.<name>.yml` | The manifest file a repo carries; the `.json` twin is also read |
|
|
223
|
+
| `state_dir` | `~/.<name>` | Per-user state: web server, daemons, logs, history |
|
|
224
|
+
| `services_dir` | `.<name>-services` | Managed clones, relative to the distribution root |
|
|
225
|
+
| `workspaces_dir` | `<name>-workspaces` | Workspace checkouts, relative to the distribution root |
|
|
226
|
+
|
|
227
|
+
Env vars, with `ACME` as the prefix:
|
|
228
|
+
|
|
229
|
+
| Variable | What |
|
|
230
|
+
| ----------------- | ------------------------------------------------------------------ |
|
|
231
|
+
| `ACME_ROOT` | The distribution root, if Den cannot find it from the entry script |
|
|
232
|
+
| `ACME_HOME` | Overrides `state_dir` (two instances on one machine stay apart) |
|
|
233
|
+
| `DEN_ROOT` | The same as `<PREFIX>_ROOT`; the shim sets it |
|
|
234
|
+
| `DEN_ENGINE_ROOT` | Den's package directory; `bin/den` sets it |
|
|
235
|
+
| `DEN_PROFILE` | Read another profile file instead of `<root>/den.yml` (tests) |
|
|
236
|
+
|
|
237
|
+
## Brand
|
|
238
|
+
|
|
239
|
+
What people see: the CLI banner and help header, web page titles and the
|
|
240
|
+
edge's web route. Read from `brand:` in the org config; every field is
|
|
241
|
+
optional.
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
brand:
|
|
245
|
+
name: Acme # default: the product name, first letter upper-cased
|
|
246
|
+
tagline: Acme local dev and E2E harness # default: "Local dev and E2E harness"
|
|
247
|
+
banner: # optional ASCII-art lines; default: the name spelled out
|
|
248
|
+
- " ┌───────────┐"
|
|
249
|
+
- " │ A C M E │"
|
|
250
|
+
- " └───────────┘"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
| Field | Used for |
|
|
254
|
+
| --------- | ---------------------------------------------------------------------------- |
|
|
255
|
+
| `name` | Web page `<title>`s, the banner fallback, the web route on the edge (`acme`) |
|
|
256
|
+
| `tagline` | The line under the banner |
|
|
257
|
+
| `banner` | The CLI and web server startup banner |
|
|
258
|
+
|
|
259
|
+
Runtime names (env vars, files, directories) always come from `den.yml`,
|
|
260
|
+
never from the brand.
|
|
261
|
+
|
|
262
|
+
## The bin shim
|
|
263
|
+
|
|
264
|
+
`bin/<cli>` is three lines of sh: it names the distribution root and runs
|
|
265
|
+
Den from `node_modules`.
|
|
266
|
+
|
|
267
|
+
```sh
|
|
268
|
+
#!/bin/sh
|
|
269
|
+
DEN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
270
|
+
export DEN_ROOT; exec "$DEN_ROOT/node_modules/@monster-orange/den/bin/den" "$@"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`package.json` also lists it under `bin`, so `npm link` (or a global
|
|
274
|
+
install of the distribution) puts `acme` on your PATH.
|
|
275
|
+
|
|
276
|
+
Den's own `bin/den` sets `DEN_ENGINE_ROOT` to its own package directory and
|
|
277
|
+
sets `DEN_ROOT` only when it is unset and the engine directory holds a
|
|
278
|
+
`den.yml` (Den's own checkout). An installed Den ships no `den.yml`, so the
|
|
279
|
+
engine directory is never taken for a distribution. `DEN_USE_DIST=1` still
|
|
280
|
+
runs a compiled `dist/` build when one exists.
|
|
281
|
+
|
|
282
|
+
## make: den.mk
|
|
283
|
+
|
|
284
|
+
A distribution's `Makefile` includes Den's targets from the package:
|
|
285
|
+
|
|
286
|
+
```make
|
|
287
|
+
DEN_TARGET_PREFIX := acme
|
|
288
|
+
include node_modules/@monster-orange/den/make/den.mk
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`DEN_TARGET_PREFIX` names the service and setup targets: `make acme-up`,
|
|
292
|
+
`acme-down`, `acme-status`, `acme-logs`, `acme-graph`, `acme-workspace`,
|
|
293
|
+
`acme-setup` and the rest (default `den`). `den create` sets it to the CLI
|
|
294
|
+
name.
|
|
295
|
+
|
|
296
|
+
`den.mk` defines:
|
|
297
|
+
|
|
298
|
+
| Variable | What |
|
|
299
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
300
|
+
| `DEN_ENGINE` | Den's package directory (the directory above `den.mk`) |
|
|
301
|
+
| `DEN_TSX` | The tsx binary: Den's own, or the one npm hoisted into `node_modules` |
|
|
302
|
+
| `DEN_PLAYWRIGHT` | The playwright binary, found the same way |
|
|
303
|
+
| `DEN_BIN` | `$(DEN_ENGINE)/bin/den` |
|
|
304
|
+
| `DEN_ROOT` | Exported: the directory make runs in (`$(CURDIR)`) |
|
|
305
|
+
|
|
306
|
+
and includes `make/test.mk`, `local_dev.mk`, `journeys.mk`, `security.mk` and
|
|
307
|
+
`demo.mk`: `make test`, `make web`, `make <prefix>-up`, `make test-syn-all
|
|
308
|
+
repo=<repo>`, `make test-smk-all repo=<repo>`, `make test-perf
|
|
309
|
+
module=<module>`, `make test-jrn-all`, `make test-sec-all` and the rest.
|
|
310
|
+
Recipes run from the distribution root (reports and staged tests land there)
|
|
311
|
+
and reach Den's files through `$(DEN_ENGINE)`. `make help` lists the main
|
|
312
|
+
targets; define your own `help` by setting `DEN_OWN_HELP := 1` before the
|
|
313
|
+
include. Add your own targets below it.
|
|
314
|
+
|
|
315
|
+
## Two roots
|
|
316
|
+
|
|
317
|
+
Den resolves two directories (`src/shared/paths.ts`, `src/shared/engine.ts`):
|
|
318
|
+
|
|
319
|
+
- the **engine root** (`getEngineRoot()`, `enginePath()`): Den's own files,
|
|
320
|
+
`src/`, `make/`, `scripts/`; `node_modules/@monster-orange/den` in a
|
|
321
|
+
distribution;
|
|
322
|
+
- the **distribution root** (`getDistRoot()`, `distPath()`): `den.yml`,
|
|
323
|
+
config, manifests, `tests/pillars/`, reports, results, staged tests.
|
|
324
|
+
|
|
325
|
+
Den's scripts run with the engine's tsx (`tsxCommand()`), never through `npx`
|
|
326
|
+
or a path relative to the current directory. In Den's own checkout both roots
|
|
327
|
+
are the same directory.
|
|
328
|
+
|
|
329
|
+
## Running the web UI as a service (macOS)
|
|
330
|
+
|
|
331
|
+
Den ships a launchd installer that runs the web UI at login and restarts it if
|
|
332
|
+
it exits. From the distribution root:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
DEN_ROOT="$PWD" DEN_SERVICE_LABEL=local.acme.web \
|
|
336
|
+
node_modules/@monster-orange/den/service/install.sh # install or refresh
|
|
337
|
+
node_modules/@monster-orange/den/service/install.sh status # with the same env
|
|
338
|
+
node_modules/@monster-orange/den/service/install.sh uninstall
|
|
339
|
+
node_modules/@monster-orange/den/service/install.sh print # the plist only
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
| Variable | Default |
|
|
343
|
+
| ------------------- | ---------------------------------------- |
|
|
344
|
+
| `DEN_ROOT` | required in a distribution |
|
|
345
|
+
| `DEN_SERVICE_LABEL` | `local.<distribution dir name>.web` |
|
|
346
|
+
| `DEN_SERVICE_LOGS` | `~/Library/Logs/<distribution dir name>` |
|
|
347
|
+
|
|
348
|
+
The service runs the engine's server with the `node` on your `PATH` at install
|
|
349
|
+
time, from the distribution root; re-run `install` after changing node versions
|
|
350
|
+
or upgrading Den. Keep the label stable: it is how launchd knows the service.
|
|
351
|
+
|
|
352
|
+
## MCP server
|
|
353
|
+
|
|
354
|
+
`./bin/acme mcp` runs an [MCP](https://modelcontextprotocol.io) server over
|
|
355
|
+
stdio, so an agent (an MCP client such as an editor or a coding agent) can
|
|
356
|
+
read and, where the org allows it, act on the same local environment the web
|
|
357
|
+
UI shows. It is a thin client of the running web server
|
|
358
|
+
(`http://localhost:<web.port>`): agents and the UI share one state and one
|
|
359
|
+
set of guards. It never starts the web server; if it is not running, every
|
|
360
|
+
tool answers with the command that starts it (`./bin/acme web up`). stdout
|
|
361
|
+
carries only the protocol; diagnostics go to stderr.
|
|
362
|
+
|
|
363
|
+
The web server keeps running the Den it started with until it is restarted,
|
|
364
|
+
so after an upgrade it can be older than the MCP server. When a tool's route
|
|
365
|
+
answers 404, the MCP server reads the web server's version from
|
|
366
|
+
`/api/server-info` and, if it predates the route, says so:
|
|
367
|
+
`web server is Den 0.1.0; stacks needs >= 0.2.0: run acme web restart`. Any
|
|
368
|
+
other 404 is reported as it is.
|
|
369
|
+
|
|
370
|
+
Register it with a client as a stdio server, for example:
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"mcpServers": {
|
|
375
|
+
"acme": { "command": "/path/to/acme/bin/acme", "args": ["mcp"] }
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
`--port <n>` points it at a web server on another port.
|
|
381
|
+
|
|
382
|
+
### Config
|
|
383
|
+
|
|
384
|
+
Without an `mcp:` block in the org config (`config/<name>.yml`) only the read
|
|
385
|
+
tools are registered. Actions are opt-in, by name:
|
|
386
|
+
|
|
387
|
+
```yaml
|
|
388
|
+
mcp:
|
|
389
|
+
actions:
|
|
390
|
+
[service_up, service_down, service_restart, workspace_sync, run_tests]
|
|
391
|
+
run_tests:
|
|
392
|
+
envs: [local] # the default; production is refused even if listed
|
|
393
|
+
logs:
|
|
394
|
+
remote: false # the default; true lets the log tools read non-local sources
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
An unknown action or environment name is an error, so a typo never turns a
|
|
398
|
+
guard off.
|
|
399
|
+
|
|
400
|
+
### Tools
|
|
401
|
+
|
|
402
|
+
Read tools (always registered):
|
|
403
|
+
|
|
404
|
+
| Tool | Web API | What |
|
|
405
|
+
| ------------------- | ------------------------------------------ | ---------------------------------------------------------- |
|
|
406
|
+
| `status` | `/api/health` | Service health; `url` (HTTP check) or `check` (shell) |
|
|
407
|
+
| `services` | `/api/services` | Services, their mode (managed or dev-managed) and commands |
|
|
408
|
+
| `applications` | `/api/applications` | Org > Application > Repo > Services |
|
|
409
|
+
| `graph` | `/api/graph` | The derived dependency graph and startup order |
|
|
410
|
+
| `workspaces` | `/api/workspaces` | Workspaces, active and focused |
|
|
411
|
+
| `environments` | `/api/environments` | The enabled environment names (never their values) |
|
|
412
|
+
| `logs_search` | `/api/logs/search` | Search services' full log history |
|
|
413
|
+
| `logs_tail` | `/api/service/taillog` | The last lines of a service's log (bounded, no follow) |
|
|
414
|
+
| `tests_available` | `/api/modules`, `/api/test-sources` | A pillar's modules and the repos they come from |
|
|
415
|
+
| `security_latest` | `/api/security/latest` | The newest security scan per mode |
|
|
416
|
+
| `release_status` | `/api/release/runs`, `/api/release/status` | Recent CD runs, and an env's deployed-version table |
|
|
417
|
+
| `manifest_validate` | `/api/manifest/validate` | Validate a manifest by path or content |
|
|
418
|
+
| `stacks` | `/api/stacks` | What `stack ls/ps/health` show: project, routes, health |
|
|
419
|
+
| `edge_status` | `/api/edge` | The edge: up or down, its routes and cert names |
|
|
420
|
+
|
|
421
|
+
Action tools (only those named in `mcp.actions`): `service_up`,
|
|
422
|
+
`service_down`, `service_restart` (through `/api/service/exec`),
|
|
423
|
+
`workspace_sync` (`/api/workspace/sync`) and `run_tests` (`/api/run`). There
|
|
424
|
+
is no deploy tool.
|
|
425
|
+
|
|
426
|
+
### Guards
|
|
427
|
+
|
|
428
|
+
- **Lifecycle only, local only.** The service tools run a manifest's `up`,
|
|
429
|
+
`down` or `restart` and nothing else, with `env=local`, and only for a
|
|
430
|
+
service run locally: its placement is `local` and it has a local `up`
|
|
431
|
+
command (see [Placement](#placement)).
|
|
432
|
+
- **Sync touches managed clones only.** It never pulls, resets or switches
|
|
433
|
+
branches in a dev-managed checkout (your own). The web server enforces
|
|
434
|
+
this for the UI's Sync too: a managed entry whose path is, holds or sits
|
|
435
|
+
inside a dev-managed checkout is refused, out loud.
|
|
436
|
+
- **Tests:** `run_tests` targets only `mcp.run_tests.envs` (default
|
|
437
|
+
`[local]`) and never production. A security run must first pass the
|
|
438
|
+
security CLI's own plan (`/api/security/plan`, a dry run): every target
|
|
439
|
+
host in `security.owned_hosts` and the mode within the env's ceiling.
|
|
440
|
+
`full` (active attacks) is local only.
|
|
441
|
+
- **Logs** read local sources only, unless `mcp.logs.remote: true`. All text
|
|
442
|
+
the tools return is scrubbed of secret-shaped values: bearer tokens, JWTs,
|
|
443
|
+
AWS keys, credentials in URLs and DSNs, `key=value` secrets, private-key
|
|
444
|
+
blocks.
|
|
445
|
+
- **Never exposed:** sudo passwords, AWS login, opening a terminal or editor,
|
|
446
|
+
workspace-wide exec, any other service command, settings writes, workspace
|
|
447
|
+
create, rename or mode changes, the server log, and anything that returns
|
|
448
|
+
environment values. The MCP server's HTTP client cannot reach any other
|
|
449
|
+
route.
|
|
450
|
+
|
|
451
|
+
### Audit
|
|
452
|
+
|
|
453
|
+
Every action is recorded with actor `agent`, the MCP client's name and
|
|
454
|
+
version (as the client reports them at initialize: a label, never used to
|
|
455
|
+
authorise anything), and the MCP server's pid and session id. They travel as
|
|
456
|
+
`x-den-*` headers on each web API call. The web server writes each action
|
|
457
|
+
(and each UI one) as a lifecycle line in its log; on the Logs page, the
|
|
458
|
+
`acme/server` stream shows an agent's actions as `[agent]`, ending
|
|
459
|
+
`· by agent <client> <version> (mcp pid <pid>, session <id>)`.
|
|
460
|
+
|
|
461
|
+
## Pinning and upgrading
|
|
462
|
+
|
|
463
|
+
`package.json` pins an exact Den version (`create` writes the version that
|
|
464
|
+
ran it). Den is pre-1.0: read the **Migrations** section of
|
|
465
|
+
[CHANGELOG.md](../CHANGELOG.md) for every version between yours and the
|
|
466
|
+
target, make the config and manifest changes it lists, then:
|
|
467
|
+
|
|
468
|
+
```sh
|
|
469
|
+
npm install @monster-orange/den@<version> --save-exact
|
|
470
|
+
./bin/acme --version
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Installing from a tarball (`npm pack` of a Den checkout, before a version is
|
|
474
|
+
on npm): every tarball Den hands out has its own prerelease number
|
|
475
|
+
(`0.1.0-dev.1`, `-dev.2`, …). npm caches a tarball by version and
|
|
476
|
+
integrity, so a repacked tarball with an unchanged version reinstalls the
|
|
477
|
+
old copy; if you ever repack one yourself without bumping, remove
|
|
478
|
+
`node_modules/@monster-orange/den` and its `package-lock.json` entry first.
|
|
479
|
+
|
|
480
|
+
## Developing Den against a distribution
|
|
481
|
+
|
|
482
|
+
To try a Den change in a distribution, install your checkout instead of the
|
|
483
|
+
published package:
|
|
484
|
+
|
|
485
|
+
```sh
|
|
486
|
+
cd acme
|
|
487
|
+
npm install ../den # node_modules/@monster-orange/den → your checkout
|
|
488
|
+
./bin/acme status
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
npm links the directory, so edits to Den's `src/` take effect on the next
|
|
492
|
+
run (Den runs its TypeScript with tsx; there is no build step). Den's
|
|
493
|
+
checkout has its own `den.yml`, but the shim's `DEN_ROOT` wins, so the CLI
|
|
494
|
+
still runs as the distribution. Put the pinned version back with `npm
|
|
495
|
+
install @monster-orange/den@<version> --save-exact` before committing.
|
|
496
|
+
|
|
497
|
+
To check a change the way CI does, run `scripts/dist-smoke.sh` in Den's
|
|
498
|
+
checkout: it packs Den, scaffolds `acme` from the tarball, installs the
|
|
499
|
+
tarball into it, and checks the CLI, make targets and web server.
|
package/make/demo.mk
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# make/demo.mk — end-to-end proof of the repo flow on three demo repos
|
|
2
|
+
#
|
|
3
|
+
# examples/demo/demo-api standalone API
|
|
4
|
+
# examples/demo/demo-web calls demo-api (.den.yml compose.uses)
|
|
5
|
+
# examples/demo/demo-notes unrelated, standalone
|
|
6
|
+
#
|
|
7
|
+
# Each repo carries its own Makefile (run it alone) and .den.yml (how
|
|
8
|
+
# den runs it: compose behind the HTTPS edge, no host ports).
|
|
9
|
+
#
|
|
10
|
+
# make demo register + up + check + restart + down, then clean up
|
|
11
|
+
# make demo-register workspace "demo" with the three repos
|
|
12
|
+
# make demo-apps den apps: "shop" (declared by the repos) + demo-notes (its own)
|
|
13
|
+
# make demo-up den up -A shop (demo-api first), then demo-notes
|
|
14
|
+
# make demo-check HTTPS through the edge (retries ~10s while the edge
|
|
15
|
+
# picks up new routes); demo-web shows demo-api's answer
|
|
16
|
+
# make demo-status den status
|
|
17
|
+
# make demo-restart den restart -A shop
|
|
18
|
+
# make demo-down den down, every demo repo
|
|
19
|
+
# make demo-clean down, drop the demo workspace + catalog entries, refocus
|
|
20
|
+
|
|
21
|
+
.PHONY: demo demo-apps demo-register demo-up demo-check demo-status demo-graph demo-restart demo-down demo-clean
|
|
22
|
+
|
|
23
|
+
DEMO_WS := demo
|
|
24
|
+
DEMO_REPOS := demo-api demo-web demo-notes
|
|
25
|
+
DEMO_DIR := $(DEN_ENGINE)/examples/demo
|
|
26
|
+
DEMO_PREV := $(HOME)/.den/demo-prev-focus
|
|
27
|
+
DEMO_DOMAIN = $(shell $(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/edge/config.ts").then(m=>console.log(m.readEdgeConfig().domain))' 2>/dev/null)
|
|
28
|
+
DEN_CLI := $(DEN_BIN)
|
|
29
|
+
|
|
30
|
+
# Steps run in sequence (a prerequisite list would run demo-check only once).
|
|
31
|
+
demo:
|
|
32
|
+
@for t in demo-register demo-apps demo-graph demo-up demo-check demo-restart demo-check demo-status demo-clean; do \
|
|
33
|
+
echo "\n── make $$t"; $(MAKE) --no-print-directory $$t || { $(MAKE) --no-print-directory demo-clean; exit 1; }; \
|
|
34
|
+
done
|
|
35
|
+
@echo "\n✓ demo passed"
|
|
36
|
+
|
|
37
|
+
demo-register:
|
|
38
|
+
@mkdir -p $(dir $(DEMO_PREV))
|
|
39
|
+
@[ -f $(DEMO_PREV) ] || $(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/environment-manager/workspaces.ts").then(m=>console.log(m.getFocusedWorkspaceName()??"default"))' > $(DEMO_PREV)
|
|
40
|
+
@$(DEN_CLI) workspace create $(DEMO_WS) >/dev/null
|
|
41
|
+
@$(DEN_CLI) workspace use $(DEMO_WS) >/dev/null
|
|
42
|
+
@for r in $(DEMO_REPOS); do $(DEN_CLI) register $(DEMO_DIR)/$$r; done
|
|
43
|
+
@$(DEN_CLI) workspace list
|
|
44
|
+
|
|
45
|
+
demo-apps:
|
|
46
|
+
@$(DEN_CLI) apps
|
|
47
|
+
|
|
48
|
+
demo-graph:
|
|
49
|
+
@$(DEN_CLI) up -A shop --dry-run
|
|
50
|
+
|
|
51
|
+
demo-up:
|
|
52
|
+
@$(DEN_CLI) up -A shop
|
|
53
|
+
@$(DEN_CLI) up demo-notes
|
|
54
|
+
|
|
55
|
+
demo-check:
|
|
56
|
+
@set -e; for u in api.demo-api app.demo-web app.demo-notes; do \
|
|
57
|
+
for i in 1 2 3 4 5 6 7 8 9 10; do \
|
|
58
|
+
code=$$(curl -sk -o /dev/null -w '%{http_code}' https://$$u.$(DEMO_DOMAIN)/healthz); \
|
|
59
|
+
[ "$$code" = 200 ] && break; sleep 1; \
|
|
60
|
+
done; \
|
|
61
|
+
echo "$$code https://$$u.$(DEMO_DOMAIN)/healthz"; [ "$$code" = 200 ] || exit 1; \
|
|
62
|
+
done
|
|
63
|
+
@curl -sk https://app.demo-web.$(DEMO_DOMAIN)/ | grep -q '"service": "demo-api"' \
|
|
64
|
+
&& echo "✓ demo-web reached demo-api over the link network" \
|
|
65
|
+
|| { echo "✗ demo-web did not reach demo-api"; exit 1; }
|
|
66
|
+
|
|
67
|
+
demo-status:
|
|
68
|
+
@$(DEN_CLI) status
|
|
69
|
+
|
|
70
|
+
demo-restart:
|
|
71
|
+
@$(DEN_CLI) restart -A shop
|
|
72
|
+
|
|
73
|
+
demo-down:
|
|
74
|
+
@$(DEN_CLI) down -A shop
|
|
75
|
+
@$(DEN_CLI) down demo-notes
|
|
76
|
+
|
|
77
|
+
demo-clean: demo-down
|
|
78
|
+
@$(DEN_CLI) workspace use $$(cat $(DEMO_PREV) 2>/dev/null || echo default) >/dev/null
|
|
79
|
+
@$(DEN_CLI) workspace delete $(DEMO_WS) --yes >/dev/null
|
|
80
|
+
@$(DEN_TSX) -e 'import("$(DEN_ENGINE)/src/shared/environment-manager/catalog.ts").then(m=>{for(const r of process.argv.slice(1))m.removeCatalogEntry(r)})' $(DEMO_REPOS)
|
|
81
|
+
@echo "✓ demo workspace removed; focus back on $$(cat $(DEMO_PREV) 2>/dev/null || echo default)"
|
|
82
|
+
@rm -f $(DEMO_PREV)
|
package/make/den.mk
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# make/den.mk — Den's make targets, for any distribution.
|
|
2
|
+
#
|
|
3
|
+
# A distribution's Makefile includes it from the installed package:
|
|
4
|
+
#
|
|
5
|
+
# include node_modules/@monster-orange/den/make/den.mk
|
|
6
|
+
#
|
|
7
|
+
# Den's own Makefile includes it too (include make/den.mk). Recipes run from
|
|
8
|
+
# the distribution root (the directory make runs in: config/, manifests/,
|
|
9
|
+
# reports/ and results/ live there) and reach Den's own files through
|
|
10
|
+
# $(DEN_ENGINE). In Den's checkout the two are the same directory.
|
|
11
|
+
|
|
12
|
+
# Prefix of the service and setup targets (`make <prefix>-up`, -status, …):
|
|
13
|
+
# the distribution's own name. Set it before the include; Den's own is "den".
|
|
14
|
+
DEN_TARGET_PREFIX ?= den
|
|
15
|
+
|
|
16
|
+
# Den's package root: the directory above this file.
|
|
17
|
+
DEN_ENGINE ?= $(patsubst %/,%,$(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..))
|
|
18
|
+
|
|
19
|
+
# The distribution root, and the engine, for every Den process a recipe runs.
|
|
20
|
+
DEN_ROOT ?= $(CURDIR)
|
|
21
|
+
export DEN_ROOT
|
|
22
|
+
DEN_ENGINE_ROOT := $(DEN_ENGINE)
|
|
23
|
+
export DEN_ENGINE_ROOT
|
|
24
|
+
|
|
25
|
+
# Binaries from Den's dependencies: Den's own node_modules (a checkout) or
|
|
26
|
+
# the distribution's, where npm hoists them.
|
|
27
|
+
den_bin = $(firstword $(wildcard $(DEN_ENGINE)/node_modules/.bin/$(1) $(CURDIR)/node_modules/.bin/$(1)) $(1))
|
|
28
|
+
DEN_TSX ?= $(call den_bin,tsx)
|
|
29
|
+
DEN_PLAYWRIGHT ?= $(call den_bin,playwright)
|
|
30
|
+
# The CLI (as `den`, or the distribution's own name via its den.yml).
|
|
31
|
+
DEN_BIN ?= $(DEN_ENGINE)/bin/den
|
|
32
|
+
DEN_CLI_TS ?= $(DEN_TSX) $(DEN_ENGINE)/src/ui/cli/index.ts
|
|
33
|
+
|
|
34
|
+
# ── Globals ───────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
# Environment selection — defaults to local.
|
|
37
|
+
# Usage: make test-syn-all env=staging
|
|
38
|
+
env ?= local
|
|
39
|
+
export E2E_ENVIRONMENT=$(env)
|
|
40
|
+
OPEN_REPORT ?= 0
|
|
41
|
+
|
|
42
|
+
# Secrets backend is a strategy chosen in the org config (secrets.provider:
|
|
43
|
+
# doppler | 1password | env). Override per shell:
|
|
44
|
+
# DEN_SECRETS_PROVIDER=env make up
|
|
45
|
+
# OP_ACCOUNT is only consulted when the 1password strategy is selected.
|
|
46
|
+
OP_ACCOUNT ?= example.1password.com
|
|
47
|
+
export OP_ACCOUNT
|
|
48
|
+
|
|
49
|
+
# Repo for the smoke and browser pillars — no default: make test-smk-all repo=<repo>
|
|
50
|
+
repo ?=
|
|
51
|
+
|
|
52
|
+
# ── Fragments ─────────────────────────────────────────────────────────────────
|
|
53
|
+
include $(DEN_ENGINE)/make/test.mk
|
|
54
|
+
include $(DEN_ENGINE)/make/local_dev.mk
|
|
55
|
+
include $(DEN_ENGINE)/make/journeys.mk
|
|
56
|
+
include $(DEN_ENGINE)/make/security.mk
|
|
57
|
+
include $(DEN_ENGINE)/make/demo.mk
|
|
58
|
+
|
|
59
|
+
# ── Help ──────────────────────────────────────────────────────────────────────
|
|
60
|
+
# A distribution gets `make help` from here; Den's own Makefile has a longer
|
|
61
|
+
# one and sets DEN_OWN_HELP before including this file.
|
|
62
|
+
.PHONY: $(DEN_TARGET_PREFIX)-help
|
|
63
|
+
$(DEN_TARGET_PREFIX)-help:
|
|
64
|
+
@printf '\nDen targets (run from this directory)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n'
|
|
65
|
+
@printf ' make test interactive test runner\n'
|
|
66
|
+
@printf ' make web the web UI\n'
|
|
67
|
+
@printf ' make $(DEN_TARGET_PREFIX)-up / down start / stop services\n'
|
|
68
|
+
@printf ' make $(DEN_TARGET_PREFIX)-status service status\n'
|
|
69
|
+
@printf ' make test-syn-all repo=R browser tests\n'
|
|
70
|
+
@printf ' make test-int-all API tests\n'
|
|
71
|
+
@printf ' make test-smk-all repo=R smoke tests\n'
|
|
72
|
+
@printf ' make test-perf module=M performance tests\n'
|
|
73
|
+
@printf ' make test-jrn-all journeys\n'
|
|
74
|
+
@printf ' make test-sec-all security scans\n\n'
|
|
75
|
+
|
|
76
|
+
ifndef DEN_OWN_HELP
|
|
77
|
+
.PHONY: help
|
|
78
|
+
help: $(DEN_TARGET_PREFIX)-help
|
|
79
|
+
.DEFAULT_GOAL := help
|
|
80
|
+
endif
|