Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1497,8 +1497,8 @@ Use `harness_execute(resource_type="pull_request", action="close", ...)` for an
| `fme_identity` | | | x | x | | |
| `fme_standard_segment` | x | x | | | | |
| `fme_segment_keys` | x | | | x | | |
| `fme_segment` | x | x | x | | x | |
| `fme_segment_definition` | x | x | x | x | x | |
| `fme_segment` | x | x | x | x | x | |
| `fme_segment_definition` | x | x | x | x | x | `list_keys`, `add_keys`, `remove_keys` |


**FME (Split.io) resources** — `fme_`* resources support **dual-mode scoping**: legacy calls pass `workspace_id` and hit the Split.io API (`api.split.io`); newer calls pass `org_id`+`project_id` together and hit Harness-native endpoints (standard `HARNESS_API_KEY`/`HARNESS_BASE_URL`, same auth as every other `harness_*` resource) instead. Passing both `workspace_id` and `org_id`/`project_id` on the same call, or mixing `org_id` with `project_id` alone, is an error — pick one mode per call. Every operation below is available in legacy mode, unchanged. Harness-native mode coverage is currently narrower:
Expand All @@ -1508,14 +1508,14 @@ Use `harness_execute(resource_type="pull_request", action="close", ...)` for an
- **`fme_feature_flag`** — dual-mode, both branches fully wired. Harness-native (`org_id`+`project_id`): `list`/`get`/`create`/`delete` hit `/fme/api/v4/feature-flags` (body for `create`: `name`, `trafficType`, optional `description`/`tags`/`owners`, per `CreateFeatureFlagRequest`); `update` sends a merge-patch to `/fme/api/v4/feature-flags/{name}`; `archive`/`unarchive` hit `/fme/api/v4/feature-flags/{name}/archive|unarchive` (optional `comment` only — no `title`, per `ArchiveUnarchiveRequest`); `kill`/`restore`/`reallocate` hit `/fme/api/v4/feature-flag-definitions/{name}/kill|restore|reallocate` with `environment_id` as a query param (optional `comment`/`title`, per `FeatureFlagDefinitionActionRequest`).
- **`fme_feature_flag_definition`** — `get`/`create`/`update` are wired to the real `/fme/api/v4/feature-flag-definitions` endpoint. Body shape is identical to legacy mode (`treatments`, `defaultTreatment`, `defaultRule`, optional `rules`/`baselineTreatment`/`trafficAllocation`/`comment`), plus an optional `title` field available only in Harness-native mode. `environment_id` is passed as a query param (not a path segment, unlike legacy mode).
- **`fme_rollout_status`** — `list` is not yet implemented.
- **`fme_rule_based_segment`** — (Deprecated — see `fme_segment`.) Harness-native mode is rejected on every operation (`list`/`get`/`create`/`delete`) — use `fme_segment` instead; this resource supports only the legacy `workspace_id` contract.
- **`fme_rule_based_segment_definition`** — (Deprecated — see `fme_segment_definition`.) Harness-native mode is rejected on every operation/action (`list`/`update`/`enable`/`disable`/`change_request`) — use `fme_segment_definition` instead (no `enable`/`disable`/`change_request` equivalent there); this resource supports only the legacy `workspace_id`/`environment_id` contract.
- **`fme_rule_based_segment`** — deprecated. Legacy `workspace_id` still hits Split v2. Harness-native (`org_id`+`project_id`) is rejected — use `fme_segment`.
- **`fme_rule_based_segment_definition`** — Harness-native mode is rejected (`list`/`update`/`enable`/`disable`/`change_request`). v4 has no enable/disable/change_request; environment definitions and keys live on `fme_segment_definition`.
- **`fme_traffic_type`** — `list` is not yet implemented.
- **`fme_identity`** — `create`/`update` are not yet implemented if `org_id`+`project_id` are passed together; otherwise proceeds as a normal legacy call.
- **`fme_standard_segment`** — (Deprecated — see `fme_segment`.) Harness-native mode is rejected on every operation (`list`/`get`) — use `fme_segment` instead; this resource supports only the legacy `workspace_id` contract. There is no `create` operation for this resource in either mode.
- **`fme_segment_keys`** — `list`/`update` are not yet implemented if `org_id`+`project_id` are passed together; otherwise proceeds as a normal legacy call.
- **`fme_segment`** — `list`/`get`/`create`/`delete` are wired to the real `/fme/api/v4/segments` endpoint (consolidates `fme_standard_segment`/`fme_rule_based_segment`); `create` body: `name`, `trafficType`, `type` (required — one of `standard`/`rule_based`/`large`), optional `description`/`tags`/`owners`.
- **`fme_segment_definition`** — Harness-native only (no legacy `workspace_id` support). `list`/`get`/`create`/`update`/`delete` are wired to `/fme/api/v4/segment-definitions`, per `Harness_Split/Main` PR #12644 (open, not yet merged as of this writing — paths may still change). `update` uses JSON Merge Patch on `description`, the only mutable field. There is no `enable`/`disable`/`change_request` action — the backend has no such endpoints for this unified resource.
- **`fme_standard_segment`** — deprecated. Legacy `workspace_id` still hits Split v2. Harness-native is rejected — use `fme_segment`.
- **`fme_segment_keys`** — `list`/`update` are not yet implemented if `org_id`+`project_id` are passed together; otherwise proceeds as a normal legacy call. Harness-native keys live on `fme_segment_definition` execute `list_keys`/`add_keys`/`remove_keys`.
- **`fme_segment`** — `list`/`get`/`create`/`update`/`delete` wired to `/fme/api/v4/segments`. `list` requires filter `segment_type` (`STANDARD` | `LARGE` | `RULE_BASED`; one kind per call) plus optional `status`/`offset`/`limit`. `create` body: `name`, `trafficType`, required JSON `segmentType` (same enum); optional `description`/`tags`/`owners`. MCP alias `type` (`standard` | `large` | `rule_based`) maps to `segmentType` for one release and is never sent on the wire. `update` is JSON Merge Patch (`application/merge-patch+json`) on `description`/`tags`/`owners`. GET/PATCH/DELETE have no MCP kind gate; the backend STANDARD-store lookup 404s for LARGE/RULE_BASED names.
- **`fme_segment_definition`** — Harness-native only. `list`/`get`/`create`/`update`/`delete` plus execute `list_keys`/`add_keys`/`remove_keys` on `/fme/api/v4/segment-definitions`. `update` uses JSON Merge Patch on `description`. Membership keys must be cleared before delete (400 `hasDependents` otherwise). There is no `enable`/`disable`/`change_request` action.

In single-user/self-hosted mode, legacy-mode auth uses a Bearer token from `HARNESS_FME_API_KEY`, falling back to a non-placeholder `HARNESS_API_KEY`. `HARNESS_FME_API_KEY` may be a legacy Split admin key or an FME-entitled Harness PAT/SAT, but it is rejected in `multi-user` mode so shared deployments cannot override each session user's credential. Hosted OAuth/service-routing credentials for Harness platform APIs do not authenticate direct Split.io requests. `fme_feature_flag` supports full lifecycle management in legacy mode: create (requires `traffic_type_id`), list, get, update metadata, delete, and kill/restore/reallocate/archive/unarchive execute actions. Use `fme_traffic_type` to discover traffic type IDs, `fme_identity` to create/update identity attributes, and `fme_standard_segment` / `fme_segment_keys` to inspect standard segments and add member keys. `fme_rule_based_segment` provides CRUD for targeting segments, while `fme_rule_based_segment_definition` manages environment-specific segment rules with enable/disable and change request approval flows.

Expand Down
14 changes: 10 additions & 4 deletions src/registry/scope-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,18 @@ export function isFmeHarnessNativeSelected(input: Record<string, unknown>, resou
}

/**
* Guards Harness-native-only resources (e.g. fme_segment) that have no legacy
* Split.io fallback. Unlike `resolveFmeDualMode`, missing org_id/project_id here
* must throw rather than silently falling back to config.HARNESS_ORG/HARNESS_PROJECT —
* a stray global default must never leak into an FME-adjacent call.
* Guards Harness-native-only operations that have no legacy Split.io fallback.
* Rejects workspace_id (including mixed with org/project) so new ops cannot
* dual-route. Unlike `resolveFmeDualMode`, missing org_id/project_id must throw
* rather than falling back to config.HARNESS_ORG/HARNESS_PROJECT, and the error
* must not offer workspace_id as an alternative.
*/
export function requireHarnessNativeSegmentScope(input: Record<string, unknown>, resourceType: string): void {
if (input.workspace_id) {
throw new Error(
`${resourceType}: Harness-native (org_id/project_id) only — pass org_id+project_id instead of workspace_id.`,
);
}
if (!input.org_id || !input.project_id) {
throw new Error(`${resourceType}: org_id and project_id are required (account is taken from config).`);
}
Expand Down
Loading