Skip to content

feat(cmd): add --additional-features flag for transparent feature injection#626

Merged
skevetter merged 4 commits intoskevetter:mainfrom
kurisu-dotto-komu:feat/additional-features
Mar 24, 2026
Merged

feat(cmd): add --additional-features flag for transparent feature injection#626
skevetter merged 4 commits intoskevetter:mainfrom
kurisu-dotto-komu:feat/additional-features

Conversation

@kurisu-dotto-komu
Copy link
Copy Markdown

@kurisu-dotto-komu kurisu-dotto-komu commented Mar 19, 2026

The devcontainer CLI supports --additional-features to inject features at build time without modifying project files. DevPod doesn't expose this, so users who want a consistent set of tools across workspaces must either modify each project's devcontainer.json or rely on --dotfiles, which runs post-build and misses Docker layer caching.

This adds --additional-features to the up and build commands. The flag accepts a JSON object matching the devcontainer.json "features" schema, which is serialized through the workspace-info tunnel and merged into the resolved config on the agent side before feature resolution.

Example:

devpod up <src> --additional-features '{ "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {"moby": "false"}}'

Summary by CodeRabbit

  • New Features

    • Added a new --additional-features flag to allow passing extra devcontainer features as JSON; provided features are merged into the final devcontainer configuration and can override existing feature options.
  • Tests

    • Added tests covering merge behavior, overrides, empty input, and invalid-JSON error handling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 98d3571a-09b0-452f-b241-5731ba640cad

📥 Commits

Reviewing files that changed from the base of the PR and between 41d89ed and b69b1c7.

📒 Files selected for processing (5)
  • cmd/build.go
  • cmd/up.go
  • pkg/devcontainer/config.go
  • pkg/devcontainer/config_test.go
  • pkg/provider/workspace.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/provider/workspace.go
  • cmd/build.go

📝 Walkthrough

Walkthrough

Adds a new CLI flag --additional-features (stringified JSON) to build/up commands, exposes it through CLIOptions, and merges parsed entries into the devcontainer config substitution step; includes unit tests for merge, override, invalid JSON, and empty input.

Changes

Cohort / File(s) Summary
Command Flags
cmd/build.go, cmd/up.go
Add AdditionalFeatures string field to BuildCmd and UpCmd and register a --additional-features CLI flag.
Provider Options
pkg/provider/workspace.go
Add AdditionalFeatures string to exported CLIOptions (JSON tag additionalFeatures,omitempty) so the option is propagated.
Feature Merging Logic
pkg/devcontainer/config.go
Parse options.AdditionalFeatures JSON into map[string]any when non-empty, initialize parsedConfig.Features if nil, merge parsed entries into parsedConfig.Features (via maps.Copy), and log the count and keys of merged features; returns a parse error formatted parse --additional-features JSON: %w on failure.
Feature Tests
pkg/devcontainer/config_test.go
Add tests (suppressing logs with Log: log.Discard) for empty input, valid JSON merge, merge with existing features, override behavior for duplicate keys, and invalid JSON error containing --additional-features.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as "CLI (build/up)"
  participant Cmd as "BuildCmd/UpCmd"
  participant Runner as "Runner.substitute"
  participant Config as "parsedConfig"

  User->>CLI: invoke build/up with --additional-features JSON
  CLI->>Cmd: set AdditionalFeatures field
  Cmd->>Runner: call substitute with CLI options
  Runner->>Config: load base devcontainer config
  alt AdditionalFeatures not empty
    Runner->>Runner: parse JSON into map
    Runner->>Config: ensure Features map initialized
    Runner->>Config: merge parsed features into parsedConfig.Features
    Runner->>CLI: log merged feature count/keys
  end
  Runner->>Config: continue substitution with merged config
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding a new --additional-features CLI flag across the build and up commands for feature injection.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/devcontainer/config.go`:
- Around line 209-213: The current r.Log.Infof call logs the entire
additionalFeatures map which may leak sensitive values; update the logging in
pkg/devcontainer/config.go to avoid printing the raw payload by removing the
full map from the message and either log only the count
(len(additionalFeatures)) or a sanitized list of keys (not values). Locate the
r.Log.Infof invocation referencing additionalFeatures and change it to emit a
message like "Merged %d additional feature(s)" with len(additionalFeatures) (or
a scrubbed set of keys), ensuring additionalFeatures' values are never included
in logs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 60261294-919e-4577-868c-a513200e515f

📥 Commits

Reviewing files that changed from the base of the PR and between 870e6e3 and 5f8bda1.

📒 Files selected for processing (5)
  • cmd/build.go
  • cmd/up.go
  • pkg/devcontainer/config.go
  • pkg/devcontainer/config_test.go
  • pkg/provider/workspace.go

@kurisu-dotto-komu kurisu-dotto-komu force-pushed the feat/additional-features branch from bd6730a to 1f6d9ab Compare March 19, 2026 00:33
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/devcontainer/config_test.go (1)

195-199: Consider asserting original feature options are preserved.

The merge test verifies both feature keys exist, but doesn't confirm the original feature's options ({"version": "20"}) remain intact after the merge. This would strengthen coverage against accidental mutation.

💡 Proposed enhancement
 	s.NoError(err)
 	s.Len(result.Config.Features, 2)
 	s.Contains(result.Config.Features, "ghcr.io/devcontainers/features/node:1")
 	s.Contains(result.Config.Features, "ghcr.io/devcontainers/features/git:1")
+	nodeOpts, ok := result.Config.Features["ghcr.io/devcontainers/features/node:1"].(map[string]any)
+	s.True(ok)
+	s.Equal("20", nodeOpts["version"])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/devcontainer/config_test.go` around lines 195 - 199, Add an assertion to
the test that verifies the original feature options are preserved after the
merge: check the merged config's feature entry for the node feature (accessing
result.Config.Features or the structure that holds per-feature options) and
assert its options still include the original {"version":"20"} value (or
equality to the original options object). Locate the test that currently asserts
s.Len(result.Config.Features, 2) / s.Contains(...) and add a precise assertion
against the node feature's options to ensure they weren't mutated during merge.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/devcontainer/config_test.go`:
- Around line 218-220: The current test does a non-fatal type assertion into
nodeOpts from result.Config.Features["ghcr.io/devcontainers/features/node:1"]
and then uses s.True(ok) which won't stop execution on failure, causing a nil
map panic when accessing nodeOpts["version"]; change the assertion to a fatal
check using s.Require().True(ok) (or otherwise short-circuit the test) before
accessing nodeOpts, referencing the variables and map lookup used in the snippet
(result.Config.Features and nodeOpts) so the test halts if the type assertion
fails.

---

Nitpick comments:
In `@pkg/devcontainer/config_test.go`:
- Around line 195-199: Add an assertion to the test that verifies the original
feature options are preserved after the merge: check the merged config's feature
entry for the node feature (accessing result.Config.Features or the structure
that holds per-feature options) and assert its options still include the
original {"version":"20"} value (or equality to the original options object).
Locate the test that currently asserts s.Len(result.Config.Features, 2) /
s.Contains(...) and add a precise assertion against the node feature's options
to ensure they weren't mutated during merge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b0616a26-4f25-41bf-80b1-2f48f382ab3b

📥 Commits

Reviewing files that changed from the base of the PR and between 5f8bda1 and bd6730a.

📒 Files selected for processing (1)
  • pkg/devcontainer/config_test.go

@kurisu-dotto-komu
Copy link
Copy Markdown
Author

Sorry about the force push. My agent got cute.

kurisu-dotto-komu and others added 4 commits March 24, 2026 13:34
…ection

Add `--additional-features` CLI flag to `devpod up` and `devpod build`
that accepts a JSON object matching the devcontainer.json `features`
schema. Features supplied via the flag are merged into the resolved
devcontainer config during variable substitution, with CLI values
taking precedence over config-file values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Avoid leaking potentially sensitive feature option values into logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@skevetter skevetter force-pushed the feat/additional-features branch from 1d7f772 to b69b1c7 Compare March 24, 2026 13:35
@skevetter skevetter merged commit 265b290 into skevetter:main Mar 24, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants