Skip to content

fix: resolve CLI bugs found during GA validation#31

Open
shreemaan-abhishek wants to merge 6 commits into
masterfrom
ga-readiness-validation-fixes
Open

fix: resolve CLI bugs found during GA validation#31
shreemaan-abhishek wants to merge 6 commits into
masterfrom
ga-readiness-validation-fixes

Conversation

@shreemaan-abhishek
Copy link
Copy Markdown

@shreemaan-abhishek shreemaan-abhishek commented May 14, 2026

Summary

Bug fixes surfaced while validating the a7 CLI against a real API7 EE 3.9.12 instance (the GA test plan run, Phases B–C). Each fix ships with regression coverage. Also adds the GA test plan and the resulting test report under docs/.

Bug fixes

  • ssl — flag-based ssl update silently dropped partial updates; now requires --cert/--key.
  • plugin-metadataplugin-metadata get -o yaml emitted a byte array; now passes the decoded map to the exporter.
  • pluginplugin get -o yaml emitted JSON; now honors any --output value.
  • stream-routestream-route create had no --name flag; added the Name field and validation.
  • configconfig validate silently accepted an unsupported top-level service_templates section; now rejected on the validate and diff/sync paths.

Docs

  • docs/ga-test-plan.md — the GA readiness test plan (local API7 EE 3.9.12).
  • docs/ga-test-report.md — the report from running it: bug write-ups, observations, exit-criteria assessment.

Test plan

  • go build ./..., go vet ./..., go test ./... all pass locally.
  • Unit regression tests added/updated for ssl and stream-route.
  • E2E regression tests added: TestPluginMetadata_GetYAML, TestPlugin_GetYAML, TestStreamRoute_CreateRequiresName, TestConfigValidate* (run with -tags e2e against a live instance).

Part of #22. Relates to #25 and #26.

Summary by CodeRabbit

  • Bug Fixes

    • SSL update command now validates both certificate and key flags are provided together
    • Plugin metadata and plugin YAML output formatting corrected
    • Stream-route create now requires name field
  • New Features

    • Service templates explicitly rejected in declarative configurations as unsupported
  • Documentation

    • Added GA readiness test plan and execution report documenting testing phases and identified bugs

Review Change Stack

Flag-based ssl update silently dropped partial updates. Require --cert/--key so updates do not lose fields.
Pass the decoded map to the exporter instead of json.RawMessage so -o yaml no longer renders a byte array.
plugin get -o yaml emitted JSON. Honor any --output value, not just json.
stream-route create had no --name flag. Add the Name field and validation.
config validate silently accepted a top-level service_templates section. Reject it on the validate and diff/sync paths.
Copilot AI review requested due to automatic review settings May 14, 2026 08:35
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

This PR executes a comprehensive GA readiness test plan for API7 EE 3.9.12. The test plan and detailed report document systematic testing across four phases, identify five bugs in stream-route, ssl update, plugin, and config validation commands, and implement fixes with full E2E and unit test coverage.

Changes

GA Readiness Testing & Bug Fixes

Layer / File(s) Summary
GA Test Plan and Execution Report
docs/ga-test-plan.md, docs/ga-test-report.md
Complete test plan defining four-phase execution strategy (automated E2E, manual CRUD smoke tests, unsupported resource validation, declarative config workflows), environment setup requirements, and detailed test report documenting results, five identified bugs with reproduction context and fixes, and explicit exit criteria confirmation.
Service Templates Rejection in Declarative Config
pkg/api/types_config.go, pkg/cmd/config/configutil/configutil.go, pkg/cmd/config/validate/validate.go, test/e2e/config_test.go
ConfigFile struct adds ServiceTemplates field; validation rejects it as unsupported in both the supported-sections check and explicit config file validation, with E2E test confirming the rejection error message.
Stream Route Name Field Requirement
pkg/api/types_stream_route.go, pkg/cmd/stream-route/create/create.go, pkg/cmd/stream-route/create/create_test.go, test/e2e/stream_route_test.go
StreamRoute type gains required Name field; create command adds --name flag and validates the field for both flag-based and file-based creation paths, with unit and E2E tests confirming the requirement is enforced before API calls.
SSL Update Flag-Based Validation
pkg/cmd/ssl/update/update.go, pkg/cmd/ssl/update/update_test.go, test/e2e/ssl_test.go
SSL update command validates both --cert and --key flags are present for flag-based updates, preventing partial updates that would lose certificate material; unit tests assert the validation guards and E2E test confirms successful update with both flags and error handling without them.
Plugin & Plugin-Metadata YAML Output Format Fixes
pkg/cmd/plugin-metadata/get/get.go, pkg/cmd/plugin/get/get.go, test/e2e/plugin_metadata_test.go, test/e2e/plugin_test.go
plugin-metadata get exports decoded metadata structure for YAML output instead of raw response bytes; plugin get honors --output flag for all formats (not just JSON); E2E tests validate both commands produce correctly formatted YAML output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • api7/a7#21: Both PRs extend config validation to reject unsupported top-level sections (service_templates in this PR, non-EE resources in the retrieved PR), using the same validation path in pkg/cmd/config/configutil/ValidateSupportedSections.

Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security Check ❌ Error Cert/key material exposed in test error messages via %#v formatting. Config validation allows empty service_templates to bypass checks. Remove %#v from update_test.go error messages. Use != nil instead of len() > 0 for service_templates checks in validate.go and configutil.go.
E2e Test Quality Review ⚠️ Warning Three issues: (1) SSL test logs cert/key material in error. (2) service_templates validation allows empty arrays. (3) Tests are comprehensive but must fix these first. Remove cert/key logging from ssl/update/update_test.go:91. Change service_templates validation from len() > 0 to != nil in configutil.go:245 and validate.go:106.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: resolve CLI bugs found during GA validation' directly and clearly summarizes the main change—resolving CLI bugs identified during GA validation testing.
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.
✨ 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 ga-readiness-validation-fixes

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: 4

🧹 Nitpick comments (1)
test/e2e/ssl_test.go (1)

176-181: ⚡ Quick win

Strengthen the failed-update assertion to prevent false positives.

After the rejected update, you assert old SNI exists, but not that the new SNI is absent. Adding that check makes the regression stricter.

Suggested test hardening
 	snis := requireJSONArray(t, ssl["snis"], "ssl.snis")
 	assert.Contains(t, snis, "require-cert.example.com")
+	assert.NotContains(t, snis, "require-cert-updated.example.com")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/ssl_test.go` around lines 176 - 181, The test currently checks that
the original SNI ("require-cert.example.com") remains after a rejected update
but doesn't assert the new (rejected) SNI is absent; update the assertion block
around the ssl lookup (using runA7JSON, requireJSONArray and the snis variable)
to also assert that the rejected/new SNI value is not present (e.g., add an
assert.NotContains(t, snis, "<new-sni-host>") after the existing
assert.Contains) so the test fails if the rejected update accidentally added the
new SNI.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/ga-test-plan.md`:
- Around line 26-30: The fenced code block containing the environment variables
(A7_ADMIN_URL, A7_TOKEN, A7_GATEWAY_GROUP) is missing a language tag which
triggers MD040; update the opening fence to include a language (e.g., "text") so
it becomes ```text to satisfy markdown linting while keeping the block content
unchanged.

In `@pkg/cmd/config/configutil/configutil.go`:
- Around line 245-247: The validator currently only rejects service_templates
when cfg.ServiceTemplates has items; change the check to also reject an
explicitly set empty section by testing for a non-nil slice instead of length.
Replace the condition using len(cfg.ServiceTemplates) with a check like
cfg.ServiceTemplates != nil (or cfg.ServiceTemplates != nil ||
len(cfg.ServiceTemplates) > 0) so that an explicit service_templates: [] is
treated as unsupported and appended to the unsupported list (referencing
cfg.ServiceTemplates and the unsupported variable in configutil.go).

In `@pkg/cmd/config/validate/validate.go`:
- Around line 106-108: The current check only rejects non-empty slices
(len(cfg.ServiceTemplates) > 0) and therefore allows an explicitly-present empty
section; change the condition to detect presence instead of length by checking
for nil (if cfg.ServiceTemplates != nil) and append the same error to errs.
Update the validate logic that references cfg.ServiceTemplates and errs in
validate.go so any explicitly-provided service_templates (including []) is
rejected.

In `@pkg/cmd/ssl/update/update_test.go`:
- Around line 90-92: The test currently serializes the SSL payload (body) into
the error using "%#v", which can expose cert/key material; update the assertion
in update_test.go so that when the check on body.Cert and body.Key fails you
return a non-sensitive error message (e.g., "unexpected cert/key in payload" or
include only boolean context), removing any serialization of body, Cert, or Key
values; ensure the failing message references only that the cert/key did not
match expected flags and does not print the payload contents.

---

Nitpick comments:
In `@test/e2e/ssl_test.go`:
- Around line 176-181: The test currently checks that the original SNI
("require-cert.example.com") remains after a rejected update but doesn't assert
the new (rejected) SNI is absent; update the assertion block around the ssl
lookup (using runA7JSON, requireJSONArray and the snis variable) to also assert
that the rejected/new SNI value is not present (e.g., add an
assert.NotContains(t, snis, "<new-sni-host>") after the existing
assert.Contains) so the test fails if the rejected update accidentally added the
new SNI.
🪄 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: 893f658c-30f9-424c-840f-6a38143ea3ea

📥 Commits

Reviewing files that changed from the base of the PR and between 7b67da5 and 1a6e0f7.

📒 Files selected for processing (17)
  • docs/ga-test-plan.md
  • docs/ga-test-report.md
  • pkg/api/types_config.go
  • pkg/api/types_stream_route.go
  • pkg/cmd/config/configutil/configutil.go
  • pkg/cmd/config/validate/validate.go
  • pkg/cmd/plugin-metadata/get/get.go
  • pkg/cmd/plugin/get/get.go
  • pkg/cmd/ssl/update/update.go
  • pkg/cmd/ssl/update/update_test.go
  • pkg/cmd/stream-route/create/create.go
  • pkg/cmd/stream-route/create/create_test.go
  • test/e2e/config_test.go
  • test/e2e/plugin_metadata_test.go
  • test/e2e/plugin_test.go
  • test/e2e/ssl_test.go
  • test/e2e/stream_route_test.go

Comment thread docs/ga-test-plan.md
Comment on lines +26 to +30
```
A7_ADMIN_URL = https://localhost:7443 # control-plane HTTPS port — confirm
A7_TOKEN = a7ee-<your-access-token> # access token from the dashboard UI / API
A7_GATEWAY_GROUP = default # resolved to a UUID at runtime
```
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 | ⚡ Quick win

Add a language tag to the fenced block to satisfy markdown linting.

The block starting at Line 26 is missing a fence language (MD040).

Suggested fix
-```
+```text
 A7_ADMIN_URL   = https://localhost:7443      # control-plane HTTPS port — confirm
 A7_TOKEN       = a7ee-<your-access-token>    # access token from the dashboard UI / API
 A7_GATEWAY_GROUP = default                   # resolved to a UUID at runtime
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 26-26: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ga-test-plan.md` around lines 26 - 30, The fenced code block containing
the environment variables (A7_ADMIN_URL, A7_TOKEN, A7_GATEWAY_GROUP) is missing
a language tag which triggers MD040; update the opening fence to include a
language (e.g., "text") so it becomes ```text to satisfy markdown linting while
keeping the block content unchanged.

Comment on lines +245 to +247
if len(cfg.ServiceTemplates) > 0 {
unsupported = append(unsupported, "service_templates")
}
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 | ⚡ Quick win

Reject explicit empty service_templates sections as well.

Current validation only rejects non-empty values; an explicit service_templates: [] can still pass even though the section is unsupported.

Suggested fix
-	if len(cfg.ServiceTemplates) > 0 {
+	if cfg.ServiceTemplates != nil {
 		unsupported = append(unsupported, "service_templates")
 	}
📝 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
if len(cfg.ServiceTemplates) > 0 {
unsupported = append(unsupported, "service_templates")
}
if cfg.ServiceTemplates != nil {
unsupported = append(unsupported, "service_templates")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/config/configutil/configutil.go` around lines 245 - 247, The
validator currently only rejects service_templates when cfg.ServiceTemplates has
items; change the check to also reject an explicitly set empty section by
testing for a non-nil slice instead of length. Replace the condition using
len(cfg.ServiceTemplates) with a check like cfg.ServiceTemplates != nil (or
cfg.ServiceTemplates != nil || len(cfg.ServiceTemplates) > 0) so that an
explicit service_templates: [] is treated as unsupported and appended to the
unsupported list (referencing cfg.ServiceTemplates and the unsupported variable
in configutil.go).

Comment on lines +106 to +108
if len(cfg.ServiceTemplates) > 0 {
errs = append(errs, "service_templates are not supported by current API7 EE")
}
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 | ⚡ Quick win

Reject explicitly-empty service_templates sections as well.

Current logic only fails when the slice is non-empty, so service_templates: [] is accepted even though the section is unsupported.

Suggested fix
-	if len(cfg.ServiceTemplates) > 0 {
+	if cfg.ServiceTemplates != nil {
 		errs = append(errs, "service_templates are not supported by current API7 EE")
 	}
📝 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
if len(cfg.ServiceTemplates) > 0 {
errs = append(errs, "service_templates are not supported by current API7 EE")
}
if cfg.ServiceTemplates != nil {
errs = append(errs, "service_templates are not supported by current API7 EE")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/config/validate/validate.go` around lines 106 - 108, The current
check only rejects non-empty slices (len(cfg.ServiceTemplates) > 0) and
therefore allows an explicitly-present empty section; change the condition to
detect presence instead of length by checking for nil (if cfg.ServiceTemplates
!= nil) and append the same error to errs. Update the validate logic that
references cfg.ServiceTemplates and errs in validate.go so any
explicitly-provided service_templates (including []) is rejected.

Comment on lines +90 to 92
if !strings.Contains(body.Cert, "NEWCERT") || !strings.Contains(body.Key, "NEWKEY") {
return httpmock.Response{}, fmt.Errorf("expected cert/key from flags in payload, got %#v", body)
}
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 | ⚡ Quick win

Avoid serializing SSL payloads in assertion errors.

The failure message includes %#v of body, which can dump cert/key material into test logs. Please keep the error message non-sensitive.

Suggested fix
-		if !strings.Contains(body.Cert, "NEWCERT") || !strings.Contains(body.Key, "NEWKEY") {
-			return httpmock.Response{}, fmt.Errorf("expected cert/key from flags in payload, got %#v", body)
-		}
+		if !strings.Contains(body.Cert, "NEWCERT") || !strings.Contains(body.Key, "NEWKEY") {
+			return httpmock.Response{}, fmt.Errorf("expected cert/key from flags in payload")
+		}

As per coding guidelines, "Do not log, serialize, or return API keys, tokens (Bearer, JWT, access_token, refresh_token), OAuth client secrets, or plugin configuration payloads without redaction".

📝 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
if !strings.Contains(body.Cert, "NEWCERT") || !strings.Contains(body.Key, "NEWKEY") {
return httpmock.Response{}, fmt.Errorf("expected cert/key from flags in payload, got %#v", body)
}
if !strings.Contains(body.Cert, "NEWCERT") || !strings.Contains(body.Key, "NEWKEY") {
return httpmock.Response{}, fmt.Errorf("expected cert/key from flags in payload")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/ssl/update/update_test.go` around lines 90 - 92, The test currently
serializes the SSL payload (body) into the error using "%#v", which can expose
cert/key material; update the assertion in update_test.go so that when the check
on body.Cert and body.Key fails you return a non-sensitive error message (e.g.,
"unexpected cert/key in payload" or include only boolean context), removing any
serialization of body, Cert, or Key values; ensure the failing message
references only that the cert/key did not match expected flags and does not
print the payload contents.

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

This PR addresses multiple correctness bugs discovered during GA validation of the a7 CLI against a real API7 EE 3.9.12 instance, and adds/updates regression coverage plus GA documentation.

Changes:

  • Fix output-format handling for plugin get and plugin-metadata get so -o yaml emits valid YAML objects (not JSON / byte arrays).
  • Fix runtime resource command validation/behavior: require --cert/--key for flag-based ssl update, add --name (and API field) for flag-based stream-route create.
  • Reject unsupported declarative service_templates sections in config validate and config diff/sync validation paths; add E2E + unit coverage and GA plan/report docs.

Reviewed changes

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

Show a summary per file
File Description
test/e2e/stream_route_test.go Adds E2E regression tests for stream-route flag create requiring --name and successful flag create round-trip assertions.
test/e2e/ssl_test.go Adds E2E regression coverage ensuring flag-based ssl update requires cert/key and does not silently drop changes.
test/e2e/plugin_test.go Adds E2E regression coverage ensuring plugin get -o yaml produces valid YAML (not JSON).
test/e2e/plugin_metadata_test.go Adds E2E regression coverage ensuring plugin-metadata get -o yaml produces a YAML map.
test/e2e/config_test.go Adds E2E coverage that config validate rejects unsupported service_templates.
pkg/cmd/stream-route/create/create.go Adds --name flag and enforces name for both file-based and flag-based stream-route creation; includes Name in request payload.
pkg/cmd/stream-route/create/create_test.go Updates/extends unit tests for required name validation in both flag and -f paths.
pkg/cmd/ssl/update/update.go Prevents flag-based partial ssl update by requiring both --cert and --key.
pkg/cmd/ssl/update/update_test.go Updates unit tests to reflect API7 EE GET behavior (no cert/key) and adds regression test for requiring cert/key.
pkg/cmd/plugin/get/get.go Ensures explicit --output is honored via exporter (yaml/json) instead of falling back to JSON.
pkg/cmd/plugin-metadata/get/get.go Exports decoded metadata map (not json.RawMessage) so YAML output is correct.
pkg/cmd/config/validate/validate.go Adds explicit validation error when service_templates is present in declarative config.
pkg/cmd/config/configutil/configutil.go Extends supported-section validation so diff/sync paths reject service_templates.
pkg/api/types_stream_route.go Adds name field to StreamRoute type to match API7 EE requirements.
pkg/api/types_config.go Adds ServiceTemplates field to detect/reject unsupported declarative section instead of silently dropping it.
docs/ga-test-plan.md Adds GA validation test plan for local API7 EE 3.9.12.
docs/ga-test-report.md Adds GA test report capturing findings, regressions, and exit-criteria assessment.

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

Comment on lines 80 to +85
if err := cmdutil.EnsureRequiredStringField(payload, "service_id", opts.ServiceID, "--service-id is required for current API7 EE"); err != nil {
return err
}
if err := cmdutil.EnsureRequiredStringField(payload, "name", opts.Name, "name is required by API7 EE; set it in the file or pass --name"); err != nil {
return err
}
Comment on lines +166 to +168
"nodes": [{"host": "127.0.0.1", "port": 3306, "weight": 1}]
}
}`, id, id)
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