feat(manifest): declare auto_upgrade so it can be set #27

Merged
forgejo-admin merged 1 commit from declare-auto-upgrade-config into main 2026-07-31 22:12:49 +00:00

Fixes the error from trying to enable auto-upgrade on celilo-mgr:

$ sudo celilo module config set lunacycle auto_upgrade true
Error: Invalid config key 'auto_upgrade' for module lunacycle.
Valid keys: hostname, app_port, domain, idp_base_url, idp_application, forge_repo, publishes

Why it failed

I had this half right in #26 and want to correct the record. The read path is unrestricted — resolveAutoUpgrade calls getModuleConfigValue(moduleId, 'auto_upgrade'), a plain (moduleId, key) lookup against the config DB with no manifest involvement. But the write path validates: module-config.ts:56-74 looks up manifest.variables.owns[] from the installed module row and rejects any key not declared there. So the key celilo reads was one no operator could set.

Declaring the variable closes that gap. After this, auto_upgrade joins the settable list:

auto_upgrade, hostname, app_port, domain, idp_base_url, idp_application, forge_repo, publishes

type: boolean and source: user are both valid per VariableTypeSchema / VariableSourceSchema.

No default, deliberately

Reads fall back to false (pickAutoUpgrade ends return fromManifest ?? false). I left the declaration defaultless rather than shipping default: true, because a module that turns on unattended production deploys for everyone who installs it is making a posture decision that belongs to the operator. The flip stays explicit and per-install.

⚠️ This does not take effect on merge

module config set reads manifestData off the installed module row, not the repo. So the declaration has to reach the host before the key becomes settable. Sequence:

  1. Merge this → Version PR → merge that → CI publishes a .netapp carrying the declaration.
  2. One more manual celilo module deploy to get that manifest onto celilo-mgr.
  3. sudo celilo module config set lunacycle auto_upgrade true — now accepted.
  4. From then on, releases roll out on their own.

Step 2 is unavoidable: it's the last manual deploy, and it's what makes the manual deploys stop.

That assumes the registry-poll subscription is executing by then — it currently isn't (timer.tick.15m fires, no registry-poll ever runs), which is being chased separately in the celilo repo. This PR makes lunacycle's side ready; it doesn't make the poll work.

Verified

Manifest parses, and auto_upgrade appears in the filtered settable-key list — the same computation whose output the error message prints. Unit suite green (58 passed). I could not run celilo module config set against it, since that needs the manifest installed on a host.

Fixes the error from trying to enable auto-upgrade on celilo-mgr: ``` $ sudo celilo module config set lunacycle auto_upgrade true Error: Invalid config key 'auto_upgrade' for module lunacycle. Valid keys: hostname, app_port, domain, idp_base_url, idp_application, forge_repo, publishes ``` ## Why it failed I had this half right in #26 and want to correct the record. The **read** path is unrestricted — `resolveAutoUpgrade` calls `getModuleConfigValue(moduleId, 'auto_upgrade')`, a plain `(moduleId, key)` lookup against the config DB with no manifest involvement. But the **write** path validates: `module-config.ts:56-74` looks up `manifest.variables.owns[]` from the installed module row and rejects any key not declared there. So the key celilo reads was one no operator could set. Declaring the variable closes that gap. After this, `auto_upgrade` joins the settable list: ``` auto_upgrade, hostname, app_port, domain, idp_base_url, idp_application, forge_repo, publishes ``` `type: boolean` and `source: user` are both valid per `VariableTypeSchema` / `VariableSourceSchema`. ## No default, deliberately Reads fall back to `false` (`pickAutoUpgrade` ends `return fromManifest ?? false`). I left the declaration defaultless rather than shipping `default: true`, because a module that turns on unattended production deploys for everyone who installs it is making a posture decision that belongs to the operator. The flip stays explicit and per-install. ## ⚠️ This does not take effect on merge `module config set` reads `manifestData` off the **installed** module row, not the repo. So the declaration has to reach the host before the key becomes settable. Sequence: 1. Merge this → Version PR → merge that → CI publishes a `.netapp` carrying the declaration. 2. **One more manual `celilo module deploy`** to get that manifest onto celilo-mgr. 3. `sudo celilo module config set lunacycle auto_upgrade true` — now accepted. 4. From then on, releases roll out on their own. Step 2 is unavoidable: it's the last manual deploy, and it's what makes the manual deploys stop. That assumes the registry-poll subscription is executing by then — it currently isn't (`timer.tick.15m` fires, no `registry-poll` ever runs), which is being chased separately in the celilo repo. This PR makes lunacycle's side ready; it doesn't make the poll work. ## Verified Manifest parses, and `auto_upgrade` appears in the filtered settable-key list — the same computation whose output the error message prints. Unit suite green (58 passed). I could not run `celilo module config set` against it, since that needs the manifest installed on a host.
feat(manifest): declare auto_upgrade so it can be set
All checks were successful
pr-validate / validate (pull_request) Successful in 15s
9eac65c3e0
`celilo module config set` validates the key against the installed manifest's
`variables.owns[]`, so the opt-in celilo's registry-poll CD reads was
unreachable:

    $ sudo celilo module config set lunacycle auto_upgrade true
    Error: Invalid config key 'auto_upgrade' for module lunacycle.
    Valid keys: hostname, app_port, domain, idp_base_url, ...

resolveAutoUpgrade (celilo module-upgrade.ts) reads that exact key back via
getModuleConfigValue, which is a plain config-DB lookup — the write path was the
only thing blocking it. Declaring the variable closes the gap.

No default. Reads fall back to false, so turning on unattended production
deploys stays an explicit per-install operator action rather than something this
module enables for everyone who installs it.

Note this only takes effect once a version carrying it has been published AND
deployed: `module config set` reads manifestData off the installed module row,
so the declaration has to land on the host before the key becomes settable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign in to join this conversation.
No description provided.