From c19db4f593b11bce9058607ad3bdc2449e674586 Mon Sep 17 00:00:00 2001 From: Jesse Turner Date: Wed, 17 Jun 2026 11:04:08 -0700 Subject: [PATCH 1/2] chore(policy): ungate guardrail policy form The guardrail form path (--target, --form-category, --form-filters, --form-effect, --form-data-path CLI options and the interactive "form" source method) was hidden behind ENABLE_GATED_FEATURES. Remove that gating so the feature is generally available: options show in --help, the runtime "not yet available" guard is dropped, and the interactive option is no longer disabled with "Coming soon". Drops the now-unused isGatedFeaturesEnabled and Option imports. Confidence: high Scope-risk: narrow --- src/cli/primitives/PolicyPrimitive.ts | 47 +++++-------------- .../tui/screens/policy/AddPolicyScreen.tsx | 7 +-- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/cli/primitives/PolicyPrimitive.ts b/src/cli/primitives/PolicyPrimitive.ts index f28bf2d7c..950416ef8 100644 --- a/src/cli/primitives/PolicyPrimitive.ts +++ b/src/cli/primitives/PolicyPrimitive.ts @@ -5,7 +5,6 @@ import { EnforcementModeSchema, PolicySchema, ValidationModeSchema } from '../.. import { detectRegion } from '../aws'; import { getPolicyGeneration, startPolicyGeneration } from '../aws/policy-generation'; import { getErrorMessage } from '../errors'; -import { isGatedFeaturesEnabled } from '../feature-flags'; import type { RemovalPreview, SchemaChange } from '../operations/remove/types'; import { runCliCommand, withCommandRunTelemetry } from '../telemetry/cli-command-run.js'; import { PolicyValidationMode, standardize } from '../telemetry/schemas/common-shapes.js'; @@ -14,7 +13,6 @@ import { type PolicyEffect, authorizationPhaseForEffect, defaultDataPathForEffec import { BasePrimitive } from './BasePrimitive'; import { SOURCE_CODE_NOTE } from './constants'; import type { AddResult, AddScreenComponent, RemovableResource } from './types'; -import { Option } from '@commander-js/extra-typings'; import type { Command } from '@commander-js/extra-typings'; import { existsSync, readFileSync } from 'fs'; @@ -287,9 +285,6 @@ export class PolicyPrimitive extends BasePrimitive(option: T): T => (isGatedFeaturesEnabled() ? option : option.hideHelp()); - addCmd .command('policy') .description('Add a policy to a policy engine') @@ -300,34 +295,19 @@ export class PolicyPrimitive extends BasePrimitive', 'Policy statement [non-interactive]') .option('-g, --generate ', 'Generate policy from natural language description [non-interactive]') .option('--gateway ', 'Deployed gateway name for policy generation [non-interactive]') - // Guardrail form flags are gated behind ENABLE_GATED_FEATURES: hidden from help when off. - .addOption(gate(new Option('--target ', 'Gateway target name for Cedar action scope [non-interactive]'))) - .addOption( - gate( - new Option( - '--form-category ', - 'Guardrail category: contentFilter, promptAttack, or sensitiveInformation [non-interactive]' - ) - ) - ) - .addOption( - gate(new Option('--form-filters ', 'Comma-separated filters for the chosen category [non-interactive]')) + .option('--target ', 'Gateway target name for Cedar action scope [non-interactive]') + .option( + '--form-category ', + 'Guardrail category: contentFilter, promptAttack, or sensitiveInformation [non-interactive]' ) - .addOption( - gate( - new Option( - '--form-effect ', - 'Policy effect: forbid, permit, or suppressOutput (default: forbid) [non-interactive]' - ) - ) + .option('--form-filters ', 'Comma-separated filters for the chosen category [non-interactive]') + .option( + '--form-effect ', + 'Policy effect: forbid, permit, or suppressOutput (default: forbid) [non-interactive]' ) - .addOption( - gate( - new Option( - '--form-data-path ', - 'Data path to evaluate, e.g. context.input.prompt (default: context.input.prompt) [non-interactive]' - ) - ) + .option( + '--form-data-path ', + 'Data path to evaluate, e.g. context.input.prompt (default: context.input.prompt) [non-interactive]' ) .option( '--validation-mode ', @@ -378,11 +358,6 @@ export class PolicyPrimitive extends BasePrimitive POLICY_SOURCE_METHOD_OPTIONS.map(opt => { const isGenerate = opt.id === 'generate'; - // Guardrail form is gated behind ENABLE_GATED_FEATURES. - const gated = opt.id === 'form' && !isGatedFeaturesEnabled(); - const disabled = gated || (isGenerate && !isEngineDeployed); + const disabled = isGenerate && !isEngineDeployed; return { id: opt.id, title: opt.title, - description: gated ? 'Coming soon' : disabled ? 'Deploy engine first' : opt.description, + description: disabled ? 'Deploy engine first' : opt.description, disabled, }; }), From c2d64b8818179fcc21bf7c4782f92c21c32824ad Mon Sep 17 00:00:00 2001 From: Jesse Turner Date: Wed, 17 Jun 2026 11:47:11 -0700 Subject: [PATCH 2/2] test(dev-server): surface project creation failures in beforeAll The dev-server integ test only recorded projectPath when create exited 0 and silently left it undefined otherwise. A transient create failure in CI then surfaced as the unhelpful "expected undefined to be truthy" in every test, hiding the real cause. Throw with the captured stderr/stdout instead, matching the createTestProject factory's behavior, so a genuine failure is actionable and a flaky one is visible. Constraint: dev-server suite needs a real installed project (skipInstall: false), so it cannot use the factory's fast default Confidence: high Scope-risk: narrow Not-tested: the specific transient create failure seen in CI (not reproducible locally) --- integ-tests/dev-server.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integ-tests/dev-server.test.ts b/integ-tests/dev-server.test.ts index 0a7fea149..ee9a694da 100644 --- a/integ-tests/dev-server.test.ts +++ b/integ-tests/dev-server.test.ts @@ -65,10 +65,12 @@ describe('integration: dev server', () => { { skipInstall: false } ); - if (result.exitCode === 0) { - const json = JSON.parse(result.stdout); - projectPath = json.projectPath; + if (result.exitCode !== 0) { + throw new Error(`Project creation failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`); } + + const json = JSON.parse(result.stdout); + projectPath = json.projectPath; }, 120000); afterEach(() => {