@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.
Files changed (255) hide show
  1. package/CHANGELOG.md +204 -0
  2. package/LICENSE +21 -0
  3. package/README.md +165 -1
  4. package/bin/den +68 -0
  5. package/docs/distributions.md +499 -0
  6. package/make/demo.mk +82 -0
  7. package/make/den.mk +80 -0
  8. package/make/journeys.mk +57 -0
  9. package/make/local_dev.mk +154 -0
  10. package/make/security.mk +59 -0
  11. package/make/test.mk +405 -0
  12. package/package.json +101 -4
  13. package/scripts/auth-configure.ts +415 -0
  14. package/scripts/heal-config.ts +92 -0
  15. package/scripts/jsonl-playwright-reporter.js +70 -0
  16. package/scripts/manifest-read.cjs +91 -0
  17. package/scripts/setup-1password.ts +570 -0
  18. package/scripts/setup-secrets.ts +149 -0
  19. package/scripts/view-results.js +156 -0
  20. package/service/install.sh +112 -0
  21. package/src/pillars/api/fixtures/index.ts +128 -0
  22. package/src/pillars/api/fixtures/openapi-validator.ts +111 -0
  23. package/src/pillars/api/global-setup.ts +103 -0
  24. package/src/pillars/api/playwright.config.ts +105 -0
  25. package/src/pillars/api/schemas/example-api.json +110 -0
  26. package/src/pillars/api/tests/health/health.spec.ts +19 -0
  27. package/src/pillars/api/tests/health/manifest.yml +6 -0
  28. package/src/pillars/browser/fixtures/index.ts +232 -0
  29. package/src/pillars/browser/fixtures/package.json +10 -0
  30. package/src/pillars/browser/global-setup.ts +140 -0
  31. package/src/pillars/browser/global-teardown.ts +48 -0
  32. package/src/pillars/browser/playwright.config.ts +212 -0
  33. package/src/pillars/browser/setup.ts +219 -0
  34. package/src/pillars/journeys/app-config.ts +237 -0
  35. package/src/pillars/journeys/discover.ts +160 -0
  36. package/src/pillars/journeys/hooks/deny-shell.cjs +44 -0
  37. package/src/pillars/journeys/observability/events.ts +288 -0
  38. package/src/pillars/journeys/observability/sdk-mapper.ts +306 -0
  39. package/src/pillars/journeys/report/friction.ts +304 -0
  40. package/src/pillars/journeys/report/junit.ts +105 -0
  41. package/src/pillars/journeys/report/render.ts +273 -0
  42. package/src/pillars/journeys/report/results.ts +323 -0
  43. package/src/pillars/journeys/run.ts +673 -0
  44. package/src/pillars/journeys/runner.ts +1025 -0
  45. package/src/pillars/journeys/sandbox.ts +403 -0
  46. package/src/pillars/journeys/spec/loader.ts +152 -0
  47. package/src/pillars/journeys/spec/schema.ts +208 -0
  48. package/src/pillars/journeys/teardown.ts +98 -0
  49. package/src/pillars/journeys/tools/browser-session.ts +219 -0
  50. package/src/pillars/journeys/tools/browser-tool.ts +914 -0
  51. package/src/pillars/journeys/tools/http-tool.ts +564 -0
  52. package/src/pillars/journeys/tools/ledger.ts +278 -0
  53. package/src/pillars/journeys/tools/snapshot-store.ts +117 -0
  54. package/src/pillars/journeys/verify/assertions.ts +502 -0
  55. package/src/pillars/journeys/verify/verdict.ts +71 -0
  56. package/src/pillars/perf/build-report.ts +36 -0
  57. package/src/pillars/perf/k6.config.js +112 -0
  58. package/src/pillars/perf/run.ts +345 -0
  59. package/src/pillars/perf/scenarios/load-profile.js +97 -0
  60. package/src/pillars/perf/staging.ts +73 -0
  61. package/src/pillars/security/discover.ts +124 -0
  62. package/src/pillars/security/findings.ts +151 -0
  63. package/src/pillars/security/plan.ts +355 -0
  64. package/src/pillars/security/run.ts +757 -0
  65. package/src/pillars/smoke/admin-probe.ts +68 -0
  66. package/src/pillars/smoke/base-url.ts +56 -0
  67. package/src/pillars/smoke/cleanup.ts +8 -0
  68. package/src/pillars/smoke/discover.ts +237 -0
  69. package/src/pillars/smoke/ensure-smoke-teardown.ts +40 -0
  70. package/src/pillars/smoke/fixture-manager.ts +217 -0
  71. package/src/pillars/smoke/fixtures.ts +468 -0
  72. package/src/pillars/smoke/global-setup-all.ts +262 -0
  73. package/src/pillars/smoke/global-setup-global.ts +262 -0
  74. package/src/pillars/smoke/global-setup.ts +273 -0
  75. package/src/pillars/smoke/global-teardown-all.ts +8 -0
  76. package/src/pillars/smoke/global-teardown-global.ts +8 -0
  77. package/src/pillars/smoke/global-teardown.ts +139 -0
  78. package/src/pillars/smoke/playwright-all.config.ts +147 -0
  79. package/src/pillars/smoke/playwright-global.config.ts +141 -0
  80. package/src/pillars/smoke/playwright.config.ts +162 -0
  81. package/src/pillars/smoke/setup-env.ts +132 -0
  82. package/src/pillars/smoke/setup-global.ts +126 -0
  83. package/src/pillars/smoke/setup.ts +115 -0
  84. package/src/pillars/smoke/smoke-repo.ts +16 -0
  85. package/src/pillars/smoke/staging.ts +49 -0
  86. package/src/pillars/suites/run.ts +147 -0
  87. package/src/scripts/configure-aws-profiles.ts +114 -0
  88. package/src/scripts/register-repos.ts +307 -0
  89. package/src/scripts/setup-default-workspace.ts +203 -0
  90. package/src/shared/agent-actor.ts +77 -0
  91. package/src/shared/applications.ts +138 -0
  92. package/src/shared/auth/api-token.ts +416 -0
  93. package/src/shared/auth/auth0-helper.ts +284 -0
  94. package/src/shared/auth/headless-login.ts +265 -0
  95. package/src/shared/auth/jwt-helper.ts +186 -0
  96. package/src/shared/auth/sudo-vault.ts +69 -0
  97. package/src/shared/auth/test-accounts.ts +98 -0
  98. package/src/shared/auth/token-injection.ts +184 -0
  99. package/src/shared/auth/token-providers/auth0.ts +80 -0
  100. package/src/shared/auth/token-providers/index.ts +182 -0
  101. package/src/shared/auth/token-refresh.ts +273 -0
  102. package/src/shared/banner.ts +15 -0
  103. package/src/shared/brand.ts +79 -0
  104. package/src/shared/cli-tabs.ts +131 -0
  105. package/src/shared/constants.ts +128 -0
  106. package/src/shared/den-config.ts +688 -0
  107. package/src/shared/dev-metrics/emit.ts +354 -0
  108. package/src/shared/edge/config.ts +229 -0
  109. package/src/shared/edge/render.ts +221 -0
  110. package/src/shared/edge/runtime.ts +268 -0
  111. package/src/shared/edge/status.ts +74 -0
  112. package/src/shared/edge/types.ts +62 -0
  113. package/src/shared/engine.ts +67 -0
  114. package/src/shared/environment/aws-profiles.ts +49 -0
  115. package/src/shared/environment/env-selector.ts +161 -0
  116. package/src/shared/environment/playwright-env.ts +82 -0
  117. package/src/shared/environment-manager/catalog.ts +77 -0
  118. package/src/shared/environment-manager/clone-guard.ts +163 -0
  119. package/src/shared/environment-manager/dag.ts +286 -0
  120. package/src/shared/environment-manager/default-workspace.ts +182 -0
  121. package/src/shared/environment-manager/derivation/alias.ts +90 -0
  122. package/src/shared/environment-manager/derivation/cache.ts +97 -0
  123. package/src/shared/environment-manager/derivation/derive-graph.ts +421 -0
  124. package/src/shared/environment-manager/derivation/derived-up.ts +354 -0
  125. package/src/shared/environment-manager/derivation/load-alias.ts +11 -0
  126. package/src/shared/environment-manager/derivation/rules-compose.ts +42 -0
  127. package/src/shared/environment-manager/derivation/rules-events.ts +50 -0
  128. package/src/shared/environment-manager/derivation/rules-http.ts +247 -0
  129. package/src/shared/environment-manager/derivation/rules-infra.ts +64 -0
  130. package/src/shared/environment-manager/derivation/rules-readiness.ts +96 -0
  131. package/src/shared/environment-manager/derivation/scan.ts +160 -0
  132. package/src/shared/environment-manager/derivation/text.ts +40 -0
  133. package/src/shared/environment-manager/derivation/types.ts +69 -0
  134. package/src/shared/environment-manager/health.ts +635 -0
  135. package/src/shared/environment-manager/index.ts +6 -0
  136. package/src/shared/environment-manager/load-applications.ts +108 -0
  137. package/src/shared/environment-manager/log-tail.ts +213 -0
  138. package/src/shared/environment-manager/make-targets.ts +78 -0
  139. package/src/shared/environment-manager/opctl.ts +335 -0
  140. package/src/shared/environment-manager/readiness.ts +93 -0
  141. package/src/shared/environment-manager/register-local.ts +72 -0
  142. package/src/shared/environment-manager/secrets-check.ts +260 -0
  143. package/src/shared/environment-manager/service-container.ts +47 -0
  144. package/src/shared/environment-manager/service-env.ts +110 -0
  145. package/src/shared/environment-manager/service-runner.ts +1603 -0
  146. package/src/shared/environment-manager/sync-targets.ts +66 -0
  147. package/src/shared/environment-manager/up-plan.ts +326 -0
  148. package/src/shared/environment-manager/workspace-manager.ts +905 -0
  149. package/src/shared/environment-manager/workspaces.ts +860 -0
  150. package/src/shared/manifest/deps.ts +27 -0
  151. package/src/shared/manifest/merge-override.ts +75 -0
  152. package/src/shared/manifest/migrate-manifest.ts +101 -0
  153. package/src/shared/manifest/placement.ts +321 -0
  154. package/src/shared/manifest/read-manifest.ts +278 -0
  155. package/src/shared/manifest/schema.ts +313 -0
  156. package/src/shared/manifest/service-links.ts +93 -0
  157. package/src/shared/manifest/validate-layers.ts +229 -0
  158. package/src/shared/manifest/validate-manifest.ts +200 -0
  159. package/src/shared/manifest/workspace-manifests.ts +92 -0
  160. package/src/shared/open-url.ts +122 -0
  161. package/src/shared/org.ts +44 -0
  162. package/src/shared/paths.ts +190 -0
  163. package/src/shared/perf/optional-fields.ts +105 -0
  164. package/src/shared/perf/report-normalizer.ts +404 -0
  165. package/src/shared/perf/report-paths.ts +19 -0
  166. package/src/shared/perf/report-store.ts +110 -0
  167. package/src/shared/perf/report-types.ts +70 -0
  168. package/src/shared/perf/test-paths.ts +25 -0
  169. package/src/shared/process/log-rotation.ts +147 -0
  170. package/src/shared/process/spawn-streaming.ts +229 -0
  171. package/src/shared/product.ts +92 -0
  172. package/src/shared/profile.ts +141 -0
  173. package/src/shared/redact.ts +107 -0
  174. package/src/shared/repo-kind.ts +32 -0
  175. package/src/shared/reporting/jsonl-reporter.ts +131 -0
  176. package/src/shared/reporting/slack-reporter.ts +340 -0
  177. package/src/shared/results/result-reader.ts +266 -0
  178. package/src/shared/results/result-writer.ts +168 -0
  179. package/src/shared/secrets/doppler.ts +126 -0
  180. package/src/shared/secrets/env.ts +48 -0
  181. package/src/shared/secrets/index.ts +197 -0
  182. package/src/shared/secrets/keys.ts +33 -0
  183. package/src/shared/secrets/onepassword.ts +75 -0
  184. package/src/shared/secrets/types.ts +52 -0
  185. package/src/shared/service-url.ts +119 -0
  186. package/src/shared/smoke/branch-resolver.ts +141 -0
  187. package/src/shared/smoke/git-remote.ts +70 -0
  188. package/src/shared/smoke/repo-cloner.ts +151 -0
  189. package/src/shared/stacks/config.ts +137 -0
  190. package/src/shared/stacks/manifest-commands.ts +118 -0
  191. package/src/shared/stacks/render.ts +253 -0
  192. package/src/shared/stacks/runtime.ts +334 -0
  193. package/src/shared/stacks/status.ts +99 -0
  194. package/src/shared/stacks/types.ts +53 -0
  195. package/src/shared/terminal/tabs.ts +212 -0
  196. package/src/shared/test-discovery/module-scanner.ts +569 -0
  197. package/src/shared/types/index.ts +701 -0
  198. package/src/shared/ui-marker.ts +19 -0
  199. package/src/ui/cli/applications-command.ts +148 -0
  200. package/src/ui/cli/config-command.ts +68 -0
  201. package/src/ui/cli/create-main.ts +9 -0
  202. package/src/ui/cli/create.ts +360 -0
  203. package/src/ui/cli/edge-command.ts +81 -0
  204. package/src/ui/cli/flag-parser.ts +246 -0
  205. package/src/ui/cli/graph-command.ts +570 -0
  206. package/src/ui/cli/health-display.ts +63 -0
  207. package/src/ui/cli/index.ts +3742 -0
  208. package/src/ui/cli/init.ts +855 -0
  209. package/src/ui/cli/invocation-target.ts +175 -0
  210. package/src/ui/cli/logs-command.ts +104 -0
  211. package/src/ui/cli/mcp-main.ts +13 -0
  212. package/src/ui/cli/mcp-stdout-guard.ts +10 -0
  213. package/src/ui/cli/module-selection.ts +31 -0
  214. package/src/ui/cli/prompts.ts +767 -0
  215. package/src/ui/cli/results-viewer.ts +436 -0
  216. package/src/ui/cli/secrets-preflight.ts +91 -0
  217. package/src/ui/cli/stack-command.ts +117 -0
  218. package/src/ui/cli/stalled-setup-recovery.ts +129 -0
  219. package/src/ui/cli/test-runner.ts +1319 -0
  220. package/src/ui/cli/web-command.ts +1073 -0
  221. package/src/ui/mcp/api.ts +284 -0
  222. package/src/ui/mcp/guards.ts +141 -0
  223. package/src/ui/mcp/server.ts +147 -0
  224. package/src/ui/mcp/tools.ts +565 -0
  225. package/src/ui/server/audit.ts +71 -0
  226. package/src/ui/server/changelog-parser.ts +105 -0
  227. package/src/ui/server/daemon-reaper.ts +129 -0
  228. package/src/ui/server/editor-manager.ts +301 -0
  229. package/src/ui/server/github-service.ts +223 -0
  230. package/src/ui/server/graph-prefs.ts +89 -0
  231. package/src/ui/server/health-row.ts +15 -0
  232. package/src/ui/server/http-helpers.ts +98 -0
  233. package/src/ui/server/index.ts +3350 -0
  234. package/src/ui/server/log-history.ts +453 -0
  235. package/src/ui/server/perf-report.ts +42 -0
  236. package/src/ui/server/public/environments.html +496 -0
  237. package/src/ui/server/public/favicon.ico +0 -0
  238. package/src/ui/server/public/graph-model.js +416 -0
  239. package/src/ui/server/public/graph.css +976 -0
  240. package/src/ui/server/public/graph.js +986 -0
  241. package/src/ui/server/public/header.js +1373 -0
  242. package/src/ui/server/public/index.html +2595 -0
  243. package/src/ui/server/public/local-dev.html +5344 -0
  244. package/src/ui/server/public/logs.html +1496 -0
  245. package/src/ui/server/public/panel.js +787 -0
  246. package/src/ui/server/public/perf-report.js +359 -0
  247. package/src/ui/server/public/release.html +2111 -0
  248. package/src/ui/server/public/services.html +1103 -0
  249. package/src/ui/server/public/workspace-picker.js +69 -0
  250. package/src/ui/server/readonly-routes.ts +200 -0
  251. package/src/ui/server/release-deploy-session.ts +246 -0
  252. package/src/ui/server/release-service.ts +1125 -0
  253. package/src/ui/server/sudo-store.ts +111 -0
  254. package/src/ui/server/ui-assets.ts +73 -0
  255. 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