Commit 178a2ce
RFC0055 Identity-Aware Routing (#3758)
* Enhance add-access-rule command UX with intuitive name-based flags
This commit improves the user experience for the add-access-rule command
by replacing the positional GUID-based SELECTOR argument with intuitive
flags that accept human-readable names and support cross-space/org resolution.
Changes:
**Command Interface:**
- Remove positional SELECTOR argument (breaking change, acceptable for unreleased feature)
- Add new flags: --source-app, --source-space, --source-org, --source-any, --selector
- Support hierarchical name resolution:
- --source-app APP_NAME (looks in current space)
- --source-app APP_NAME --source-space SPACE (cross-space in current org)
- --source-app APP_NAME --source-space SPACE --source-org ORG (cross-org)
- --source-space SPACE (space-level rule)
- --source-org ORG (org-level rule)
- --source-any (allow any authenticated app)
- --selector SELECTOR (raw GUID-based selector for advanced users)
- Validate exactly one primary source is specified
- Display verbose output showing resolved selector for transparency
**Terminology Update:**
- Rename all "target" terminology to "source" throughout codebase
- Access rules specify the source (who can access), not the target
- Update AccessRuleWithRoute.TargetName → SourceName
- Update resolveAccessRuleTarget() → resolveAccessRuleSource()
- Update access-rules list command table header: "target" → "source"
**Error Handling:**
- Provide helpful error messages when app not found in current space
- Suggest using --source-space and --source-org flags for cross-space/org access
- Follow CF CLI patterns from add-network-policy command
**Testing:**
- Add 17 comprehensive test cases for add-access-rule command
- Update 19 actor tests to use new SourceName field
- All tests passing (36/36)
**Domain Integration:**
- Add enforce_access_rules support to create-shared-domain and create-private-domain
- Add --enforce-access-rules and --access-rules-scope flags
- Update domain resource with new fields
Examples:
# Simple case - app in current space
cf add-access-rule allow-frontend apps.identity --source-app frontend-app --hostname backend
# Cross-space access
cf add-access-rule allow-other apps.identity --source-app api-client --source-space other-space --hostname backend
# Cross-org access
cf add-access-rule allow-prod apps.identity --source-app client --source-space prod-space --source-org prod-org --hostname api
# Space-level rule
cf add-access-rule allow-monitoring apps.identity --source-space monitoring --hostname api
# Org-level rule
cf add-access-rule allow-platform apps.identity --source-org platform --hostname shared-api
# Any authenticated app
cf add-access-rule allow-all apps.identity --source-any --hostname public-api
Related to: cloudfoundry/community#1438
* Remove access rule names per RFC updates
Per RFC commits 882b69a and 11752f2, access rules no longer have
user-provided names. They are identified by their selector only,
with labels/annotations used for metadata instead.
Changes:
- Removed RULE_NAME argument from add-access-rule command
- Removed Name field from AccessRule API resource
- Updated access-rules list to show 4 columns (route, selector, scope, source)
- SourceName now represents resolved app/space/org name from selector
- Updated remove-access-rule to use --selector flag instead of rule name
- Renamed DeleteAccessRule() to DeleteAccessRuleBySelector()
- Updated all tests to remove Name field references
All tests passing.
* Refine access-rules output to show separate host, domain, and path columns
Changed table format from:
route selector scope source
backend.apps.identity ... app frontend-app
To:
host domain path selector scope source
backend apps.identity ... app frontend-app
api apps.identity /metrics ... space monitoring
This provides better clarity by separating the route components into
individual columns, making it easier to scan and filter visually.
* Rebrand RFC terminology: access rules → route policies, selector → source
Complete terminology shift for identity-aware routing RFC implementation:
**Access Rules → Route Policies**
- API: /v3/access_rules → /v3/route_policies
- CLI commands:
- cf access-rules → cf route-policies
- cf add-access-rule → cf add-route-policy
- cf remove-access-rule → cf remove-route-policy
- Domain flags: --enforce-access-rules → --enforce-route-policies
- Domain fields: enforce_access_rules → enforce_route_policies,
access_rules_scope → route_policies_scope
**Selector → Source**
- API field: "selector" → "source"
- CLI flag: --selector → --source
- Query params: selectors → sources, selector_resource_guids → source_guids
- Table column headers: "selector/source" → "source/name"
- Internal types: AccessRule → RoutePolicy, AccessRuleWithRoute → RoutePolicyWithRoute
- Error types: AccessRuleNotFoundError → RoutePolicyNotFoundError
**Rationale (per RFC)**
- "Route policies" aligns with existing CF "network policies" terminology
- "Source" matches C2C network policy convention (source → destination)
- Improves clarity: policies define allowed sources that can reach routes
- Better mental model for users familiar with CF networking concepts
This is a breaking change but acceptable since RFC is pre-GA with only
POC/lab implementations. Clean terminology is preferred over backward
compatibility at this stage.
Co-authored-by: RFC Community <cloudfoundry/community#1438>
Aligns-with: cloudfoundry/community@be8d74c1
* Add name-based source flags to remove-route-policy
Extract source resolution flags (--source-app, --source-space, --source-org,
--source-any, --source) into a shared RoutePolicySourceFlags struct embedded
in both add-route-policy and remove-route-policy commands.
Previously remove-route-policy only accepted --source with a raw GUID-format
value (cf:app:<guid>, etc.), while add-route-policy supported name-based
resolution. The two commands now have matching flag sets.
* Add CAPI version check for route policy commands
Guard add-route-policy, remove-route-policy, and route-policies with an
unconditional MinimumCCAPIVersionCheck against MinVersionRoutePolicies.
Guard create-shared-domain and create-private-domain conditionally when
--enforce-route-policies is passed.
MinVersionRoutePolicies is currently a placeholder (3.999.0); a failing
test in ccversion/minimum_version_test.go keeps the TODO visible until the
real CAPI version is confirmed and the constant is updated.
* Add route policies column to cf domains output
Show a single 'route policies' column when the CAPI version supports it.
The column is blank for plain domains, 'enforced' when enforcement is on
with no scope, and 'enforced (org/space/any)' when a scope is set.
The column is gated on MinVersionRoutePolicies so it silently disappears
on older CAPI targets — no hard error, cf domains still works everywhere.
* Add cf/cli to .gitignore to prevent binary commits
* Add unit tests for route policy commands, actor, and ccv3 client
* Fix: reject --source-org with --source-app when --source-space is missing
When a user specifies --source-org with --source-app but omits --source-space,
validateSourceFlags() previously passed (treating --source-app as the sole
primary flag), and resolveSource() silently ignored --source-org, resolving
the app in the currently targeted space.
Add a pre-check in validateSourceFlags() that returns RequiredFlagsError
(--source-org and --source-space must be used together) whenever --source-org
is combined with --source-app but --source-space is absent.
* test: add scope/enforce coverage for CreatePrivateDomain in domain_test.go
Refactor CreatePrivateDomain describe block to use JustBeforeEach pattern
and add Context block for enforceAccessRules=true with non-empty scope,
mirroring the existing coverage in CreateSharedDomain.
* refactor: consolidate Add/RemoveRoutePolicyArgs into single RoutePolicyArgs
Three identical one-field structs replaced with a single shared type.
Description aligned with the existing convention in arguments.go.
* test: add dedicated tests for route_policy_source_flags and create-private-domain new flags
- route_policy_source_flags_test.go: covers all validateSourceFlags branches
(no flags, single flags, qualifier combinations, RequiredFlagsError,
ArgumentCombinationError) and all resolveSource paths (raw --source,
--source-any, --source-app with/without cross-space/org, --source-space,
--source-org, error propagation from each actor call)
- create_private_domain_command_test.go: adds coverage for --scope without
--enforce-route-policies, invalid --scope values, API version check failure,
--enforce-route-policies success (identity-aware TIP), and --scope forwarding
* test: add --enforce-route-policies and --scope coverage to create-shared-domain test
Mirrors the coverage added to create_private_domain_command_test.go:
- --scope without --enforce-route-policies returns an error
- invalid --scope value returns an error
- --enforce-route-policies with old API version returns MinimumCFAPIVersionNotMetError
- --enforce-route-policies success: identity-aware TIP, enforce=true passed to actor
- --enforce-route-policies + --scope: scope forwarded to actor
- default path now explicitly asserts enforce=false, scope empty
* refactor: extract shared --enforce-route-policies / --scope test behaviour
Introduce EnforceRoutePoliciesBehavior and ItEnforcesRoutePolicies in
enforce_route_policies_shared_test.go. Both create-shared-domain and
create-private-domain tests now delegate the duplicate When blocks to the
shared helper, parameterised only by TIPAdjective and the actor-specific
arg-extraction closures. ccversion and translatableerror imports removed from
both individual test files.
* chore: remove devbox.json and devbox.lock from tracked files
* Remove whitespace-only changes from unrelated files
Bulk find-and-replace tooling from the rebrand commit introduced
spaces→tabs indentation fixes and Invocations() mutex-lock removals
in files completely unrelated to the route-policies feature. Restore
all of them to origin/main to keep the feature diff focused.
* fix: guard AddRoutePolicy against non-enforcing domains
Add a client-side check in AddRoutePolicy that returns
DomainNotEnforcingRoutePoliciesError if the domain does not have
enforce_route_policies enabled, before attempting the API call.
CAPI already enforces this server-side (route_policies_controller.rb:129),
but the client-side guard provides a user-friendly error message with
the domain name rather than a GUID-based 422 response.
- Add actionerror.DomainNotEnforcingRoutePoliciesError
- Guard in actor/v7action/route_policy.go after domain fetch
- Update tests: set EnforceRoutePolicies on success-path domains
- Add new spec: When the domain does not enforce route policies
* refactor: move GetRoutesByDomain to route.go
Belongs alongside GetRoutesBySpace and GetRoutesByOrg rather than
in route_policy.go.
* refactor: simplify GetRoutesByDomain — drop redundant copy loop
ccv3.GetRoutes already returns []resources.Route directly;
the loop copying each element was a no-op identity conversion.
* feat: add -n short flag for --hostname on route policy commands
* refactor: extract resolveOrgGUID/resolveSpaceGUID to eliminate duplication
The org and space resolution blocks were duplicated between the
--source-app and --source-space branches of resolveSource. Extract
into standalone helpers. Add dedicated unit tests for each helper
plus the previously missing --source-space + --source-org error path.
* refactor: convert source flags test to package v7_test with v7fakes
Switch route_policy_source_flags_test.go from package v7 (internal
white-box test) to the standard package v7_test pattern used throughout
the command layer. Tests now use v7fakes.FakeActor via AddRoutePolicyCommand.Execute()
instead of an inline stub actor, which was required to work around the
circular import between package v7 and v7fakes.
resolveOrgGUID and resolveSpaceGUID are no longer tested in isolation
(they are unexported and not accessible from v7_test), but all their
code paths are covered by the resolveSource tests that exercise the full
flag-combination matrix through Execute().
* perf: use ?include=source to resolve policy source names in one API call
Replace resolveRoutePolicySource (which made a separate GetApplications/
GetSpaces/GetOrganizations call per policy) with sourceInfoFromIncluded,
a pure map lookup against resources returned by ?include=route,source.
CAPI's IncludeRoutePolicySourceDecorator already batches all referenced
app/space/org GUIDs into a single query and returns them inline, so the
route-policies command now resolves N source names with 0 extra API calls
regardless of how many policies are displayed.
* refactor: filter routes slice before map, pre-populate domain cache, add -d flag
T10: filter includedResources.Routes slice for all three conditions (domain/
hostname/path) before building routeByGUID, so the map is only populated from
matching routes.
T11: create domainCache before the filter block; when a domain filter is used,
pre-populate domainCache[domain.GUID] from the GetDomainByName result so the
subsequent cache-fill loop is a no-op for the common single-domain case.
T14: add short:'d' to the --domain flag on route-policies command.
Also replace hardcoded version string in route_policies_command_test.go with
ccversion.MinVersionRoutePolicies so the test stays valid when the constant
is updated.
* feat: register PATCH /v3/route_policies/:guid in CAPI metadata client
* feat: add RoutePolicyAmbiguityError for route-policy label disambiguation
* feat: implement GetRoutePolicyLabels and UpdateRoutePolicyLabels actor methods
- Add resolveRoutePolicyGUID helper to find policies with ambiguity/not-found error handling
- Implement GetRoutePolicyLabels to retrieve labels from route policies with optional source filtering
- Implement UpdateRoutePolicyLabels to set labels on route policies with optional source filtering
- Add comprehensive test coverage for success cases, error conditions, and edge cases
- All 1262 tests pass
* feat: add route-policy methods to Actor/SetLabelActor interfaces, regenerate fakes
* feat: add route-policy support to labels command and label updater
- Add RoutePolicy resource type to LabelsCommand.Execute() with GetRoutePolicyLabels() support
- Add RoutePolicy to LabelsCommand.checkTarget() and Resources() documentation
- Fix add_route_policy_command_test and remove_route_policy_command_test to expect correct API version 3.221.0
- Fix labels_command_test shared validation test to include route-policy in checkTarget expectations
All 2299 tests passing.
* feat: add route-policy support to cf labels command
* feat: add --source flag to set-label and unset-label commands
* fix: refactor testForResourceType helper to take explicit plural URI segment
* fix: remove orphaned comment fragment in route_policy_source_flags_test.go
* test: document that route-policy ResourceName is passed as-is to label setter
* test: document that route-policy ResourceName is passed as-is to label unsetter
* fix: remove duplicate RunSpecs in route_policy_resource_test.go
* refactor: move resolveRoutePolicyGUID to route_policy.go
The Get/UpdateRoutePolicyLabels wrappers in label.go follow the same
convention as every other resource (GetRouteLabels, GetDomainLabels,
etc.): the thin label wrapper stays in label.go and delegates GUID
resolution to a helper in the resource's own file. Move the
route-policy resolver alongside the other route-policy actor methods
and drop the now-unused ccv3 import from label.go.
* refactor: collapse resolveSource into a single org->space->app cascade
Replace the three separate --source-app/--source-space/--source-org
branches with one linear cascade: each level (org, then space, then app)
refines the GUID the next level resolves against, and the most specific
flag provided becomes the scope. The result is built once as
cf:<scope>:<guid>.
This removes the resolveOrgGUID/resolveSpaceGUID helpers, since GUID
resolution now happens exactly once per level inline. Source strings,
verbose scope output, warning ordering, and the app-not-found TIP error
are all unchanged; the existing black-box command specs cover them.
* fix: list route-policy in set-label and unset-label resource help
* feat: add -p short flag for --path on add/remove-route-policy
* Fix create-private-domain integration test SEE ALSO expectation
The related_commands tag on CreatePrivateDomainCommand was updated to
include add-route-policy and route-policies, but the integration test
still asserted the old SEE ALSO text, causing the help/usage specs to
time out waiting for a substring that no longer appears contiguously
in the rendered output.
* Set MinVersionRoutePolicies to the released CAPI version 3.224.0
capi-release 1.239.0 (https://github.com/cloudfoundry/capi-release/releases/tag/1.239.0)
ships RFC0055 Identity-Aware Routing with CC API version 3.224.0. Replace the
3.221.0 guess with the confirmed value, drop the now-obsolete placeholder
guard test, and have the command tests reference the constant instead of a
hardcoded string so they can't drift from it again.
---------
Co-authored-by: Anuj Chaudhari <chaudharianuj93@gmail.com>1 parent 9c5e2a0 commit 178a2ce
57 files changed
Lines changed: 4921 additions & 184 deletions
File tree
- actor
- actionerror
- v7action
- v7actionfakes
- api/cloudcontroller
- ccv3
- internal
- ccversion
- command
- common
- internal
- flag
- v7
- v7fakes
- integration/v7/isolated
- resources
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
Lines changed: 13 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
| 46 | + | |
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
| |||
63 | 65 | | |
64 | 66 | | |
65 | 67 | | |
| 68 | + | |
66 | 69 | | |
67 | 70 | | |
68 | 71 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
45 | 53 | | |
46 | 54 | | |
47 | 55 | | |
48 | 56 | | |
49 | 57 | | |
50 | | - | |
| 58 | + | |
51 | 59 | | |
52 | 60 | | |
53 | 61 | | |
54 | 62 | | |
55 | 63 | | |
56 | 64 | | |
57 | 65 | | |
58 | | - | |
| 66 | + | |
| 67 | + | |
59 | 68 | | |
60 | 69 | | |
61 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
62 | 79 | | |
63 | 80 | | |
64 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
112 | 112 | | |
113 | 113 | | |
114 | 114 | | |
115 | | - | |
116 | | - | |
117 | | - | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
118 | 120 | | |
119 | 121 | | |
120 | 122 | | |
121 | | - | |
| 123 | + | |
122 | 124 | | |
123 | 125 | | |
124 | 126 | | |
125 | 127 | | |
| 128 | + | |
| 129 | + | |
126 | 130 | | |
127 | 131 | | |
128 | 132 | | |
| |||
170 | 174 | | |
171 | 175 | | |
172 | 176 | | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
173 | 194 | | |
174 | 195 | | |
175 | 196 | | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
176 | 207 | | |
177 | 208 | | |
| 209 | + | |
| 210 | + | |
178 | 211 | | |
179 | 212 | | |
180 | 213 | | |
| |||
191 | 224 | | |
192 | 225 | | |
193 | 226 | | |
194 | | - | |
195 | 227 | | |
196 | 228 | | |
197 | 229 | | |
| |||
205 | 237 | | |
206 | 238 | | |
207 | 239 | | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
208 | 257 | | |
209 | 258 | | |
210 | 259 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
0 commit comments