Skip to content

fix(client): security hardening - #234

Merged
david-ruiz-cko merged 5 commits into
masterfrom
fix/INT-1772-request-building
Nov 6, 2026
Merged

david-ruiz-cko merged 5 commits into
masterfrom
fix/INT-1772-request-building

Conversation

@david-ruiz-cko

@david-ruiz-cko david-ruiz-cko commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Security hardening (reported internally): input validation for request paths. Identifiers passed to client methods are percent-encoded by the SDK, and invalid identifiers raise CheckoutArgumentException before any request is sent (see Breaking changes). Request paths for valid identifiers are unchanged.

Changes

  • lib/checkout_sdk/checkout_utils.rb: new encode_path_segment, RFC 3986 path segment encoding (unreserved characters kept, everything else percent-encoded as UTF-8) with input validation.
  • lib/checkout_sdk/client.rb: build_path encodes every argument with encode_path_segment.
  • lib/checkout_sdk/apm/bacs/bacs_client.rb: multi-segment private constant split into single segments; request path unchanged.
  • lib/checkout_sdk/apm/previous/sepa/sepa_client.rb: same, for the four mandate operations.
  • lib/checkout_sdk/instruments/instruments_client.rb: same, for get_bank_account_field_formatting.
  • lib/checkout_sdk/payments/setups/payment_setups_client.rb: input validation.
  • README.md: Exception handling, identifier encoding and when CheckoutArgumentException is raised.
  • spec/checkout_sdk/client_spec.rb: new, path building, request paths through Faraday's test adapter, and the request paths of the split constants.
  • spec/checkout_sdk/checkout_utils_spec.rb: encode_path_segment.
  • spec/checkout_sdk/payments/setups/payment_setups_client_spec.rb: input validation.

API Reference

None.

Breaking changes ⚠️

  • Client methods validate identifiers and path parameters and raise CheckoutSdk::CheckoutArgumentException for invalid values before sending a request. The rules are in the README, Exception handling.
  • Identifiers are percent-encoded by the SDK. An identifier that the caller had already encoded is encoded again (SKU%201 is sent as SKU%25201).
  • Migration: pass identifiers unencoded, and validate or rescue CheckoutArgumentException where identifiers come from user input.

Tests

  • Existing tests pass (unit suite and rubocop lib; integration tests run in CI against the sandbox)
  • Serialization tests cover every new or changed property (no request or response properties changed)
  • README updated if documented usage changed (Exception handling)

Related

None.

@david-ruiz-cko
david-ruiz-cko requested a review from a team November 5, 2026 09:41
@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown

🟢 Risk Classification: LOW

Approval route: AI Auto-Approval
Rollback controls: Automated Instant Rollback + feature flags

Classification reasons

  • no_low_class_matched
  • prod_source_modified
  • 2.2.6_logical_extension:All changes are internal refactors of existing path-building logic (splitting concatenated string constants into separate segments, adding percent-encoding to build_path, and adding input validation), reusing existing endpoints and abstractions without adding new external integrations, persisted data, auth changes, or new services.

Operational gates

  • ✅ jira_ticket (INT-1772)
  • ✅ independent_review

Files analysed: 9


wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
no_low_class_matched informational §2.2 (fall-through) None of the deterministic Low classes (§2.2.3, §2.2.4, §2.2.7, docs-only) applied; classifier fell through to LLM evaluation.
prod_source_modified informational §2.1 M7 (informational) At least one file is non-doc, non-test, non-IaC — i.e. application source code was modified.
2.2.6_logical_extension — All changes are internal refactors of existing path-building logic (splitting concatenated string constants into separate segments, adding percent-encoding to build_path, and adding input validation), reusing existing endpoints and abstractions without adding new external integrations, persisted data, auth changes, or new services. classifying §2.2.6 Sonnet 4.6 evaluator promoted minor → low: the change reuses existing code paths and does not cross a trust boundary.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@agent-wall-e agent-wall-e Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Auto-approved — this PR meets all Low-risk criteria.

All checks passed, no unresolved comments, and the change classification is:

  • no_low_class_matched
  • prod_source_modified
  • 2.2.6_logical_extension:This refactors internal path-building helpers (splitting compound string constants, adding percent-encoding, and input validation) using only existing code paths and abstractions, with no new endpoints, external integrations, persisted data, auth changes, or background processes.

wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@david-ruiz-cko david-ruiz-cko changed the title build path upgrade fix(client): security hardening Nov 5, 2026
@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown

🟡 Risk Classification: MINOR

Approval route: AI Review + Human Approval
Rollback controls: Staged rollout + rollback

Classification reasons

  • exceeds_bounded_scope:280>250

Operational gates

  • ✅ jira_ticket (INT-1772)
  • ✅ independent_review

Files analysed: 10


wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
exceeds_bounded_scope — 280>250 classifying §2.1 M8 More than 250 non-test, non-doc, non-lockfile lines changed.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown

🟢 Advisory review: Looks good to me

This PR still needs a human approval — wall-e cannot auto-approve it. For what it's worth, I read the diff and found nothing I'd block on.

This PR adds path-segment validation and percent-encoding to build_path to prevent path traversal via caller-supplied identifiers. The implementation, refactoring, and tests all look correct and consistent with the stated intent.

What I checked

  • The encode_path_segment validation correctly rejects nil, empty string, ., .., and segments containing /, \, or control characters (U+0000–U+001F, U+007F) via the regex [/\\\x00-\x1F\x7F].
  • The dot-segment check (INVALID_PATH_SEGMENTS.include?(encoded)) happens after percent-encoding, so a literal . or .. input is caught, but an encoded form like %2E%2E is correctly allowed through as a single opaque segment.
  • The refactoring of compound constants (e.g., BACS_NOTIFICATIONS → BACS + NOTIFICATIONS, SEPA_MANDATES → SEPA + MANDATES, VALIDATION/bank-accounts → VALIDATION + BANK_ACCOUNTS) correctly preserves the original URL paths as verified by the new path-level tests.
  • The payment_method_name validation in PaymentSetupsClient uses PAYMENT_METHOD_NAME_PATTERN = /\A[a-z0-9_]+\z/i which checks before build_path is called, so traversal via method name is blocked independently; the tests confirm that dots, hyphens, spaces, slashes, and query/fragment characters are all rejected.
  • The utf8_bytes fallback uses .b on the raw bytes when UTF-8 encoding fails, which means a string in a non-ASCII-compatible encoding with forbidden bytes will still be caught by FORBIDDEN_PATH_SEGMENT_BYTES; the .. UTF-16LE test confirms this path works.
  • The encode_path_segment check for to_s not returning a String is sound: it calls value.to_s and then does text.is_a?(String), which correctly catches objects where to_s is overridden to return a non-String.
  • Tests added cover the new validation logic thoroughly including edge cases (non-ASCII, alternate encodings, Integer/Symbol inputs, on-the-wire integration tests), and no existing tests are weakened or removed.
  • The README documentation accurately describes the new behaviour (unencoded inputs, pre-request raise, forbidden values).

This is not an approval. wall-e cannot auto-approve this PR — it is an opinion to help whoever does. Advisory review · us.anthropic.claude-sonnet-4-6 · wall-e 2026.06.19-02

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown

🟡 Risk Classification: MINOR

Approval route: AI Review + Human Approval
Rollback controls: Staged rollout + rollback

Classification reasons

  • exceeds_bounded_scope:336>250

Operational gates

  • ✅ jira_ticket (UTF-8)
  • ✅ independent_review

Files analysed: 12


wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
exceeds_bounded_scope — 336>250 classifying §2.1 M8 More than 250 non-test, non-doc, non-lockfile lines changed.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown

🟡 Risk Classification: MINOR

Approval route: AI Review + Human Approval
Rollback controls: Staged rollout + rollback

Classification reasons

  • exceeds_bounded_scope:336>250

Operational gates

  • ✅ jira_ticket (UTF-8)
  • ✅ independent_review

Files analysed: 12


wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@agent-wall-e

agent-wall-e Bot commented Nov 5, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
exceeds_bounded_scope — 336>250 classifying §2.1 M8 More than 250 non-test, non-doc, non-lockfile lines changed.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@agent-wall-e

agent-wall-e Bot commented Nov 6, 2026

Copy link
Copy Markdown

🟡 Risk Classification: MINOR

Approval route: AI Review + Human Approval
Rollback controls: Staged rollout + rollback

Classification reasons

  • exceeds_bounded_scope:336>250

Operational gates

  • ✅ jira_ticket (UTF-8)
  • ✅ independent_review

Files analysed: 12


wall-e 2026.06.19-02 · policy 6b4ce2b3b45a…

@agent-wall-e

agent-wall-e Bot commented Nov 6, 2026

Copy link
Copy Markdown
🔬 Debug — why this classification?

Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.

Reason code Kind Clause Meaning
exceeds_bounded_scope — 336>250 classifying §2.1 M8 More than 250 non-test, non-doc, non-lockfile lines changed.

Kinds:

  • classifying — this rule contributed to the chosen tier.
  • informational — context only; did not by itself decide the tier.

See issue #3 for the proposal to formalise this map as Appendix A of the standards doc.

wall-e 2026.06.19-02 · debug

@sonarqubecloud

sonarqubecloud Bot commented Nov 6, 2026

Copy link
Copy Markdown

@david-ruiz-cko
david-ruiz-cko merged commit 2fbf17b into master Nov 6, 2026
5 checks passed
@david-ruiz-cko
david-ruiz-cko deleted the fix/INT-1772-request-building branch November 6, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants