apple / apple/container

[Feature]: `system property ls`: design the plugin-properties contract before extending output (follow-up to #607)

Open
#1,645 1 comment 0 reactions 1 assignee Claimed by @katiewasnothere View on GitHub
Dominant language
Swift
Stars
49.9k
Forks
1.8k
Avg merge
1d 20h
Merged PRs (30d)
22

Description

This is a scoping follow-up to #607, which asks `container system property ls` to surface plugin settings alongside core configuration. After investigating the codebase and running a throwaway plugin against the live system, the request can't be cleanly resolved by only changing `PropertyList` — there's no producer side. This issue proposes the contract and a staged plan.

### Current state (as of `3512373`)

1. **`property ls` only knows the seven hardcoded sections** (`build`, `container`, `dns`, `kernel`, `network`, `registry`, `vminit`). `Application.PropertyList.run()` (`Sources/ContainerCommands/System/Property/PropertyList.swift:44`) loads `ContainerSystemConfig` and renders it. `ContainerSystemConfig.init(from:)` (`Sources/ContainerPersistence/ContainerSystemConfig.swift:63-72`) only `decodeIfPresent`s those seven keys.
2. **`[plugin.]` sections in `config.toml` are silently dropped** at decode time. No warning, no error — they parse fine, then go nowhere. Verified end-to-end: writing `[plugin.container-hello]` with three keys produces zero diagnostic and zero output in `property ls`.
3. **Infrastructure for plugin-scoped config exists but has no production conformers.** `ConfigurationLoader.loadForPlugin` (`Sources/ContainerPersistence/ConfigurationLoader.swift:123`) scopes a TOML snapshot to `plugin.` and decodes it. `LoadablePluginConfiguration` is only conformed to by test fixtures (`Tests/ContainerPersistenceTests/ConfigurationLoaderTests.swift:36,53,64`).
4. **No in-tree plugin declares any user-tunable property.** The three plugins (`container-core-images`, `container-network-vmnet`, `container-runtime-linux`) ship `config.toml` files containing only manifest metadata (`abstract`, `author`, `version`, `servicesConfig`). All current per-plugin knobs are CLI flags or hardcoded (e.g. `RuntimeLinuxHelper+Start.swift:66-72` has a literal `FIXME: should be configurable elsewhere`).

So `property ls` has no producer to read from. The issue is implicitly asking the project to design that producer.

### Why a raw `[plugin.*]` passthrough isn't enough

A minimal fix that emits whatever the user wrote under `[plugin.*]` would:
- show nothing for plugins the user hasn't touched (defeats discoverability),
- echo back typos and stale keys without validation (silently misleading),
- not lay groundwork for `property get/set/unset`.

### Proposal

Two-PR plan:

**PR 1 — define the contract.**
- Extend the plugin manifest (`Sources/ContainerPlugin/PluginConfig.swift`) with an optional `[properties]` table: each entry declares `type`, `default`, and `description`. Loaded at discovery time by `DefaultPluginFactory.create` (`Sources/ContainerPlugin/PluginFactory.swift:56-78`). Optional — zero impact on existing plugins.
- Extend `PropertyList.run()` to enumerate plugins via `PluginLoader.findPlugins()`, read each plugin's declared schema, layer in the user's actual values via `ConfigurationLoader.loadForPlugin` for plugins that conform to `LoadablePluginConfiguration` (or via a generic snapshot read otherwise), and merge into the TOML/JSON output.
- Emit a warning for any `[plugin.]` section in `config.toml` whose `` doesn't match a discovered plugin, instead of dropping silently.

**PR 2 — migrate one real plugin to prove the path.**
- Pick `container-network-vmnet`. Promote its `--variant` CLI flag (`NetworkVmnetHelper+Start.swift:62-68`) into a declared property under `[plugin.container-network-vmnet]`. Have the API server read it via `loadForPlugin` when starting the helper. Now `property ls` has a non-empty plugin section to display in the real install.

### Out of scope (follow-ups)

- `system property get/set/unset` for plugin-scoped keys (needs decisions about validation and write paths).
- The CLI-plugin invocation naming quirk surfaced while testing this — users have to type `container container-foo` because `DefaultCommand` looks up plugins by literal directory name (`DefaultCommand.swift:84`, `PluginLoader.findPlugin` `PluginLoader.swift:179-200`). Unrelated to property output, worth its own issue.

### References

- Original request: #607

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.