Skip to content

Feat/add policies#2

Merged
sedkis merged 13 commits intomainfrom
feat/add-policies
Feb 18, 2026
Merged

Feat/add policies#2
sedkis merged 13 commits intomainfrom
feat/add-policies

Conversation

@sedkis
Copy link
Owner

@sedkis sedkis commented Feb 18, 2026

No description provided.

sedkis and others added 13 commits February 18, 2026 07:45
- PolicyFile, PolicyMetadata, PolicySpec, AccessEntry for YAML policy files
- DashboardPolicy, AccessRight, DashboardPolicyListResponse for wire format
- Duration type with custom YAML unmarshal accepting string ("30d") and integer (60)
- ValidationError and ValidationErrors for structured error reporting
- Acceptance test: YAML round-trip preserves all fields
- Acceptance test: JSON round-trip preserves access_rights map
- Unit tests: Duration unmarshal, AccessEntry selectors, list response

Step-ID: 01-01
Co-Authored-By: Claude <noreply@anthropic.com>
… 01-02

- ListPolicies: GET /api/portal/policies?p={page}, parses DashboardPolicyListResponse
- GetPolicy: GET /api/portal/policies/{id}, returns structured ErrorResponse on 404
- CreatePolicy: POST /api/portal/policies with DashboardPolicy JSON body
- UpdatePolicy: PUT /api/portal/policies/{id} with DashboardPolicy JSON body
- DeletePolicy: DELETE /api/portal/policies/{id}, returns structured ErrorResponse on 404
- All methods follow doRequest/handleResponse pattern from client.go
- 8 unit tests covering happy paths and error responses

Step-ID: 01-02
Co-Authored-By: Claude <noreply@anthropic.com>
…nd bidirectional converter - step 01-03

- ParseDuration: converts "30d"->2592000, "1h"->3600, "60"->60, "0"->0; rejects abc/negative/fractional/mixed
- FormatDuration: converts seconds to largest clean unit (86400->"1d", 3600->"1h", 90->"90s")
- ValidatePolicy: collects all errors (missing fields, invalid durations, selector constraints) with field paths
- Selector resolver: name/listenPath/id resolve to exactly one API; tags resolve to >=1; fuzzy suggestions on zero-match
- CLIToWire and WireToCLI: bidirectional conversion with round-trip equivalence
- All pure logic, no HTTP dependency; 17 tests passing

Step-ID: 01-03
Co-Authored-By: Claude <noreply@anthropic.com>
- NewPolicyCommand() cobra tree with "list" subcommand
- Table output: ID, Name, APIs count, Tags columns to stdout
- Empty inventory shows "No policies found" to stderr
- JSON output with policies array, page, and count to stdout
- Network errors return ExitError{Code: 1} with message to stderr
- Registered policy command in root.go alongside api and config
- 6 unit tests covering: empty list, populated table, JSON output,
  pagination, network error, command registration

Acceptance test: TestPolicyList_WithPolicies
Unit tests: 6 new
Refactoring: L1+L2+L3 continuous

Step-ID: 02-01
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix get tests to use RunE directly via executePolicyGetCmd helper,
  matching the pattern from executePolicyListCmd; Execute() traverses
  to root and prints help instead of running the subcommand handler
- Remove t.Skip from TestPolicyGet_NotFound, enable all 3 get tests
- All 3 get scenarios pass: human YAML output, JSON output, 404 not-found
- All 6 list tests remain green; full suite passes

Step-ID: 02-02

Co-Authored-By: Claude <noreply@anthropic.com>
- Add apply subcommand with -f flag (file or stdin via -f -)
- Idempotent upsert: create when policy ID not found, update when exists
- Selector resolution against live API list: name, listenPath, id, tags
- Validation errors (missing fields, invalid duration, bad selector) return exit code 2
- Duration parsing (1m, 30d, 24h) converted to seconds in wire format
- 9 tests: create, update, listenPath selector, duration conversion,
  name not found, ambiguous, missing ID, invalid duration, file not found

Step-ID: 02-03

Co-Authored-By: Claude <noreply@anthropic.com>
- Add NewPolicyDeleteCommand with --yes flag for non-interactive deletion
- Fetch policy before delete to verify existence and show name in confirmation
- Non-existent policy returns exit code 3 with "not found" message
- JSON output mode produces structured {policy_id, operation, success} to stdout
- Human output prints confirmation with policy name to stderr
- Register delete subcommand in NewPolicyCommand alongside list, get, apply
- Enable and fix 3 scaffolded delete tests using executePolicyDeleteCmd helper
- Update registration test to verify delete subcommand presence

Step-ID: 02-04

Co-Authored-By: Claude <noreply@anthropic.com>
…tep 03-01

- Add `tyk policy init --id <id> --name <name>` subcommand that generates
  scaffold YAML to policies/{id}.yaml with sensible defaults (rate limit,
  quota, keyTTL, placeholder access entry)
- Init refuses to overwrite existing files, works offline (no Dashboard needed)
- Add full walking skeleton integration test exercising list->apply->list->get->delete
  lifecycle against an httptest mock server
- Acceptance test: 3 init tests + 1 integration test (4 total, within budget)
- Refactoring: L1+L2+L3 continuous

Step-ID: 03-01
Co-Authored-By: Claude <noreply@anthropic.com>
…st, archive

- L1-L4 refactoring across all policy files (readability, complexity, responsibilities)
- Add MarshalJSON nil-handling test to close mutation testing gap (81.82% efficacy)
- Archive evolution document to docs/evolution/
- Clean up feature working directory (design, distill, execution-log, roadmap)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sedkis sedkis merged commit 98b70b5 into main Feb 18, 2026
1 check passed
@sedkis sedkis deleted the feat/add-policies branch February 18, 2026 18:36
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.

1 participant

Comments