Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1530,8 +1530,8 @@ Typical workflow:
| `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 @@ -1541,15 +1541,14 @@ Typical workflow:
- **`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` remain dual-mode (`workspace_id` or `org_id`+`project_id`). `list`/`delete`/`kill`/`restore`/`reallocate` are Harness-native only (`org_id`+`project_id`) — MCP never had a `workspace_id` contract for those ops. Native list requires `feature_flag_name` and uses `offset`/`limit` (default 100, max 100); it does not take `environment_id`. Delete and execute require `environment_id`. Kill/restore/reallocate are the same actions as on `fme_feature_flag`. Get/create/update body matches legacy (`treatments`, `defaultTreatment`, `defaultRule`, optional `rules`/`baselineTreatment`/`trafficAllocation`/`comment`), plus optional `title` in Harness-native mode. Native update is JSON Merge Patch.
- **`fme_rollout_status`** — dual-mode `list`. Pass `org_id`+`project_id` (preferred) or the deprecated `workspace_id`. Native pagination uses `offset`/`limit` (max 100; `harness_list` `size` maps to `limit`); results are promoted to `items`/`total`. Each item has `id`, `name`, and optional `description`.

- **`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_traffic_type`** — dual-mode `list`. Pass `org_id`+`project_id` (preferred) or the deprecated `workspace_id`. Native pagination uses `offset`/`limit` (max 100; `harness_list` `size` maps to `limit`); results are promoted to `items`/`total`. Each item has `id` and `name` (no `displayAttributeId`).
- **`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
Loading