Skip to content

fix: honor secret create file positional id#13

Merged
guoqqqi merged 5 commits intomasterfrom
codex/secret-create-file-id
Apr 30, 2026
Merged

fix: honor secret create file positional id#13
guoqqqi merged 5 commits intomasterfrom
codex/secret-create-file-id

Conversation

@guoqqqi
Copy link
Copy Markdown
Contributor

@guoqqqi guoqqqi commented Apr 28, 2026

Summary

  • Make a7 secret create <provider/id> -f file inject the positional provider ID into the file payload.
  • Add unit coverage for file-based secret creation using the positional ID.
  • Turn the secret CRUD E2E create step into a real assertion instead of silently skipping on create failure.

Validation

  • go test ./pkg/cmd/secret/create ./pkg/cmd/secret/update ./pkg/cmd/secret/get ./pkg/cmd/secret/list ./pkg/cmd/secret/delete
  • go test -c -tags=e2e ./test/e2e
  • go test ./...
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes

    • Secret creation from a file now enforces a non-empty, trimmed ID (accepts --id or positional) and fails early with a clear error if missing or blank.
    • Secret get output now shows the provider-local secret ID instead of a manager-prefixed identifier.
  • Tests

    • Added tests covering file-based secret creation (including blank-ID cases) and updated end-to-end assertions; CLI create failures now surface as test failures.

Copilot AI review requested due to automatic review settings April 28, 2026 17:23
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

When creating a secret from a file, the CLI now enforces a non-empty id in the request payload: --id is written into the payload when provided; otherwise the command errors early if the file payload lacks a non-blank id. Unit and e2e tests were added/updated accordingly.

Changes

Cohort / File(s) Summary
File-Based Secret Creation
pkg/cmd/secret/create/create.go
Enforce presence of a trimmed, non-empty payload["id"] when --file is used. If --id provided, write it into payload["id"]; else require existing non-blank id, error early if missing.
Unit Tests
pkg/cmd/secret/create/create_test.go
Adds tests covering: PUT behavior when positional Options.ID is supplied with --file, error cases when neither positional ID nor valid id in file is present (including whitespace-only id). Adds temp-file/path imports.
End-to-end Test
test/e2e/secret_test.go
TestSecret_CRUD now fails immediately on a7 secret create errors and checks that a7 secret get -o json returns the provider-local id (e2e-secret-crud) rather than a manager-prefixed identifier.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (CLI)
  participant CLI as Create Command
  participant Payload as Payload (file/flags)
  participant HTTP as HTTP Client
  participant Server as API Server

  User->>CLI: run `a7 secret create --file ...` [maybe --id]
  CLI->>Payload: load JSON from file and read flags
  CLI->>Payload: if --id provided -> set payload["id"]=trim(--id)
  CLI->>Payload: else ensure payload["id"] exists and trimmed non-empty -> else error
  CLI->>HTTP: build request (PUT if id present, else POST) with payload
  HTTP->>Server: send request
  Server-->>HTTP: response
  HTTP-->>CLI: return response
  CLI-->>User: print result / error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Security Check ❌ Error Code exposes sensitive authentication credentials without redaction in command output. The api.Secret struct contains a Token field that is serialized and output to stdout in multiple contexts without proper masking. Implement a custom MarshalJSON() method on api.Secret struct to redact Token field, update test mocks to exclude tokens, and apply redaction pattern to other sensitive fields.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: ensuring the positional ID argument is honored when creating a secret from a file.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
E2e Test Quality Review ✅ Passed PR demonstrates solid E2E test quality with comprehensive coverage of create/read/update/delete operations, proper unit test scenarios with boundary cases, thorough error handling, and direct alignment with stated requirements.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/secret-create-file-id

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI review requested due to automatic review settings April 29, 2026 14:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/e2e/secret_test.go
var secret map[string]interface{}
runA7JSON(t, env, &secret, "secret", "get", secretID, "-g", gatewayGroup, "-o", "json")
assert.Equal(t, secretID, secret["id"])
assert.Equal(t, "e2e-secret-crud", secret["id"])
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The E2E JSON assertion now expects only the suffix ("e2e-secret-crud"), but the CLI/API elsewhere (e.g., pkg/cmd/secret/get tests) treats id as the full compound ID ("vault/"). Since secretID is "vault/e2e-secret-crud", this will likely fail or mask regressions. Consider asserting against secretID (or explicitly document/justify why the API returns a stripped id here).

Suggested change
assert.Equal(t, "e2e-secret-crud", secret["id"])
assert.Equal(t, secretID, secret["id"])

Copilot uses AI. Check for mistakes.
Comment thread pkg/cmd/secret/create/create.go Outdated
return err
}
if opts.ID != "" {
payload["id"] = opts.ID
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

In file mode, if the user runs a7 secret create -f <file> without a positional ID/--id and the file also omits id, this code will still POST the payload. That contradicts the documented workflow (docs/user-guide/secret.md shows create requires a compound ID) and can lead to confusing server-side errors or unintended auto-generated IDs. Suggest validating that either opts.ID is set or the loaded payload already contains id, and returning the same "secret provider id is required; use a positional arg or --id" error when neither is present.

Suggested change
payload["id"] = opts.ID
payload["id"] = opts.ID
} else {
if id, ok := payload["id"]; !ok || id == nil {
return fmt.Errorf("secret provider id is required; use a positional arg or --id")
}

Copilot uses AI. Check for mistakes.
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 `@test/e2e/secret_test.go`:
- Around line 78-80: The test asserts the short secret id but the command
returns the raw API id (prefixed); update the expectation in
test/e2e/secret_test.go to assert the full id "vault/e2e-secret-crud" (or
alternatively add normalization in pkg/cmd/secret/get/get.go to strip the
"vault/" prefix before printing), referencing the code path that uses item.ID
and the unmarshaling in pkg/api/types_secret.go so the test matches the actual
output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97a8f56a-340c-4397-8fc7-4a498ccd6d96

📥 Commits

Reviewing files that changed from the base of the PR and between 024dacd and e7d3330.

📒 Files selected for processing (3)
  • pkg/cmd/secret/create/create.go
  • pkg/cmd/secret/create/create_test.go
  • test/e2e/secret_test.go

Comment thread test/e2e/secret_test.go
Comment on lines +78 to 80
assert.Equal(t, "e2e-secret-crud", secret["id"])
assert.Equal(t, "https://vault.example.com", secret["uri"])
assert.Equal(t, "kv/apisix", secret["prefix"])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Expect the full secret id here, or normalize it in the command first.

pkg/cmd/secret/get/get.go returns item.ID as the API sent it, and pkg/api/types_secret.go unmarshals id unchanged. Without a separate normalization layer, this assertion should expect vault/e2e-secret-crud, not just e2e-secret-crud.

Suggested fix
-	assert.Equal(t, "e2e-secret-crud", secret["id"])
+	assert.Equal(t, "vault/e2e-secret-crud", secret["id"])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert.Equal(t, "e2e-secret-crud", secret["id"])
assert.Equal(t, "https://vault.example.com", secret["uri"])
assert.Equal(t, "kv/apisix", secret["prefix"])
assert.Equal(t, "vault/e2e-secret-crud", secret["id"])
assert.Equal(t, "https://vault.example.com", secret["uri"])
assert.Equal(t, "kv/apisix", secret["prefix"])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/secret_test.go` around lines 78 - 80, The test asserts the short
secret id but the command returns the raw API id (prefixed); update the
expectation in test/e2e/secret_test.go to assert the full id
"vault/e2e-secret-crud" (or alternatively add normalization in
pkg/cmd/secret/get/get.go to strip the "vault/" prefix before printing),
referencing the code path that uses item.ID and the unmarshaling in
pkg/api/types_secret.go so the test matches the actual output.

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/cmd/secret/create/create.go`:
- Around line 82-86: Reject whitespace-only IDs by trimming before validation
and assignment: when handling opts.ID, call strings.TrimSpace(opts.ID) and if
the result is empty return the same error instead of accepting it, and assign
the trimmed value to payload["id"]; similarly, when checking payload["id"] use
strings.TrimSpace(fmt.Sprint(id)) == "" (or convert+trim once) to detect and
reject whitespace-only values. Also ensure the strings package is imported.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a7555c5-939b-43c8-be27-0ca3efcaec44

📥 Commits

Reviewing files that changed from the base of the PR and between e7d3330 and f8dfd92.

📒 Files selected for processing (3)
  • pkg/cmd/secret/create/create.go
  • pkg/cmd/secret/create/create_test.go
  • test/e2e/secret_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/e2e/secret_test.go
  • pkg/cmd/secret/create/create_test.go

Comment thread pkg/cmd/secret/create/create.go
Copilot AI review requested due to automatic review settings April 29, 2026 18:00
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +89 to +98
id, ok := payload["id"]
if !ok || id == nil {
return fmt.Errorf("secret provider id is required; use a positional arg or --id")
}
trimmedID := strings.TrimSpace(fmt.Sprint(id))
if trimmedID == "" {
return fmt.Errorf("secret provider id is required; use a positional arg or --id")
}
payload["id"] = trimmedID
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

After the new ID enforcement/normalization, payload["id"] is always set for --file runs (either from opts.ID or validated from the file). The later if id, ok := payload["id"]; ok { ... } else { ... } means the POST branch is now effectively unreachable in file mode. Consider simplifying this path to always issue the PUT-by-id request once the ID is guaranteed, to reduce dead/duplicated control flow.

Copilot uses AI. Check for mistakes.
Comment thread test/e2e/secret_test.go
Comment on lines +78 to +80
// The runtime secret provider API returns the provider-local ID; the CLI
// still uses the compound ID for addressing resources.
assert.Equal(t, "e2e-secret-crud", secret["id"])
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

This assertion hard-codes the provider-local ID ("e2e-secret-crud") while the test defines secretID as the compound manager/id. To avoid the test becoming inconsistent if secretID changes, derive the expected provider-local ID from secretID (e.g., split on the first '/').

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +86
if opts.ID != "" {
id := strings.TrimSpace(opts.ID)
if id == "" {
return fmt.Errorf("secret provider id is required; use a positional arg or --id")
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

In file mode you now trim/validate opts.ID, but in the non-file path the only check is opts.ID == "". That means a7 secret create " " --uri ... (or --id " ") will pass local validation and fail later at the API, which is inconsistent with the stricter behavior added for file-based create. Consider normalizing/validating the ID (trim + non-empty) once and reusing it for both file and non-file modes (and ideally rejecting non-string payload["id"] rather than fmt.Sprint-coercing it).

Copilot uses AI. Check for mistakes.
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.

🧹 Nitpick comments (1)
pkg/cmd/secret/create/create_test.go (1)

105-153: Optional: extract shared file-test setup into helpers.

TempDir file creation and Options construction are repeated; a small helper would reduce duplication and keep future test additions cleaner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/cmd/secret/create/create_test.go` around lines 105 - 153, The two tests
TestCreateSecret_FileRequiresID and TestCreateSecret_FileRejectsWhitespaceID
duplicate TempDir file creation, writing JSON to a file, building ios, registry
and constructing an Options struct for actionRun; extract that repeated setup
into a small helper (e.g., newSecretFileTest or setupSecretFileTest) that
returns (ios, registry, filePath, Options) or returns components needed (ios,
registry, filePath, baseOptions) so both tests call the helper to create the
temp file with provided JSON content and get a prepopulated Options (IO, Client
func using registry.GetClient, Config func returning mockConfig, GatewayGroup)
then set/override only the File field and call actionRun, keeping test
assertions unchanged (referencing TestCreateSecret_FileRequiresID,
TestCreateSecret_FileRejectsWhitespaceID, actionRun, Options, File, mockConfig,
registry).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/cmd/secret/create/create_test.go`:
- Around line 105-153: The two tests TestCreateSecret_FileRequiresID and
TestCreateSecret_FileRejectsWhitespaceID duplicate TempDir file creation,
writing JSON to a file, building ios, registry and constructing an Options
struct for actionRun; extract that repeated setup into a small helper (e.g.,
newSecretFileTest or setupSecretFileTest) that returns (ios, registry, filePath,
Options) or returns components needed (ios, registry, filePath, baseOptions) so
both tests call the helper to create the temp file with provided JSON content
and get a prepopulated Options (IO, Client func using registry.GetClient, Config
func returning mockConfig, GatewayGroup) then set/override only the File field
and call actionRun, keeping test assertions unchanged (referencing
TestCreateSecret_FileRequiresID, TestCreateSecret_FileRejectsWhitespaceID,
actionRun, Options, File, mockConfig, registry).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a354970-3c3a-4154-9a19-53d035391a0c

📥 Commits

Reviewing files that changed from the base of the PR and between f8dfd92 and 7ac9d5e.

📒 Files selected for processing (2)
  • pkg/cmd/secret/create/create.go
  • pkg/cmd/secret/create/create_test.go

@guoqqqi guoqqqi merged commit 18d8bad into master Apr 30, 2026
10 checks passed
@guoqqqi guoqqqi deleted the codex/secret-create-file-id branch April 30, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants