@openwop/openwop-conformance 1.162.0 → 2.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/cli.js +54 -1
- package/dist/lib/paths.js +25 -3
- package/dist/lib/requirement-ids.js +34 -4
- package/dist/lib/scenario-disposition.js +1 -0
- package/dist/lib/spec-coherence.js +13 -32
- package/dist/spec-artifacts.lock.json +5 -0
- package/package.json +11 -33
- package/requirements.json +20303 -11809
- package/scenario-majors.json +1343 -0
- package/schemas/CORPUS-STAMP.json +138 -6
- package/src/cli.ts +47 -1
- package/src/global-setup.ts +3 -2
- package/src/lib/corpus-stamp.ts +29 -1
- package/src/lib/paths.ts +25 -3
- package/src/lib/requirement-ids.ts +33 -4
- package/src/lib/scenario-disposition.ts +1 -0
- package/src/lib/spec-coherence.ts +15 -32
- package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
- package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
- package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
- package/src/scenarios/a2a-peer-authority.test.ts +7 -6
- package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
- package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
- package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
- package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
- package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
- package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
- package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
- package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
- package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
- package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
- package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
- package/src/scenarios/agent-deployment-shape.test.ts +22 -24
- package/src/scenarios/agent-eval-run.test.ts +19 -18
- package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
- package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
- package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
- package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
- package/src/scenarios/agent-live-structured-output.test.ts +7 -6
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
- package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
- package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
- package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
- package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
- package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
- package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
- package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
- package/src/scenarios/agent-platform-profile.test.ts +18 -19
- package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
- package/src/scenarios/agent-roster-attribution.test.ts +18 -17
- package/src/scenarios/agent-roster-shape.test.ts +17 -19
- package/src/scenarios/agent-verifier-shape.test.ts +11 -11
- package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
- package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
- package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
- package/src/scenarios/agentMessageReducer.test.ts +2 -1
- package/src/scenarios/agentMetadata.test.ts +2 -1
- package/src/scenarios/agentPackCatalog.test.ts +23 -21
- package/src/scenarios/agentPackExport.test.ts +4 -2
- package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
- package/src/scenarios/agentPackInstall.test.ts +4 -2
- package/src/scenarios/agentPackProvenance.test.ts +2 -1
- package/src/scenarios/agentReasoningEvents.test.ts +3 -2
- package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
- package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
- package/src/scenarios/ai-envelope-shape.test.ts +31 -29
- package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
- package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
- package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
- package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
- package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
- package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
- package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
- package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
- package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
- package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
- package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
- package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
- package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
- package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
- package/src/scenarios/append-ordering.test.ts +7 -5
- package/src/scenarios/approval-gate-events.test.ts +4 -3
- package/src/scenarios/approval-gate-flow.test.ts +4 -3
- package/src/scenarios/approval-payload.test.ts +5 -4
- package/src/scenarios/artifact-auth.test.ts +7 -6
- package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
- package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
- package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
- package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
- package/src/scenarios/audit-log-integrity.test.ts +8 -6
- package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
- package/src/scenarios/auth-mtls.test.ts +22 -20
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
- package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
- package/src/scenarios/auth-saml-profile.test.ts +14 -12
- package/src/scenarios/auth-scim-profile.test.ts +3 -2
- package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
- package/src/scenarios/auth-subject-link.test.ts +11 -10
- package/src/scenarios/auth.test.ts +5 -4
- package/src/scenarios/authorization-fail-closed.test.ts +3 -2
- package/src/scenarios/authorization-roles-shape.test.ts +9 -7
- package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/blob-presign-expiry.test.ts +12 -10
- package/src/scenarios/blob-roundtrip.test.ts +0 -0
- package/src/scenarios/budget-enforcement.test.ts +15 -14
- package/src/scenarios/budget-policy-shape.test.ts +18 -19
- package/src/scenarios/bulk-cancel.test.ts +9 -8
- package/src/scenarios/byok-auth-modes.test.ts +13 -14
- package/src/scenarios/byok-roundtrip.test.ts +12 -10
- package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
- package/src/scenarios/callai-multimodal.test.ts +5 -3
- package/src/scenarios/cancellation.test.ts +6 -5
- package/src/scenarios/cap-breach.test.ts +15 -14
- package/src/scenarios/capability-arm-witness.test.ts +5 -3
- package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
- package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
- package/src/scenarios/certification-bundle-v2.test.ts +11 -10
- package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
- package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
- package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
- package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
- package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
- package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
- package/src/scenarios/channel-presence-shape.test.ts +11 -12
- package/src/scenarios/channel-ttl.test.ts +6 -5
- package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
- package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/commitment-fired.test.ts +6 -5
- package/src/scenarios/compensation-behavior.test.ts +24 -23
- package/src/scenarios/compensation-recovery.test.ts +28 -27
- package/src/scenarios/configurable-schema.test.ts +8 -6
- package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
- package/src/scenarios/conformance-execution-witness.test.ts +9 -8
- package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
- package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
- package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
- package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
- package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
- package/src/scenarios/connection-provider-resolution.test.ts +18 -16
- package/src/scenarios/connector-manifest-validity.test.ts +8 -7
- package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
- package/src/scenarios/context-summarization-replay.test.ts +14 -12
- package/src/scenarios/contract-provenance.test.ts +18 -18
- package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
- package/src/scenarios/conversationLifecycle.test.ts +2 -1
- package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
- package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
- package/src/scenarios/core-standard-profile.test.ts +8 -9
- package/src/scenarios/cost-attribution.test.ts +23 -21
- package/src/scenarios/credential-payload-redaction.test.ts +4 -3
- package/src/scenarios/credentials-capability-shape.test.ts +5 -4
- package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
- package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
- package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
- package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
- package/src/scenarios/data-residency-admission.test.ts +15 -14
- package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
- package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
- package/src/scenarios/debugBundle.test.ts +25 -23
- package/src/scenarios/discovery-families-view.test.ts +5 -4
- package/src/scenarios/discovery.test.ts +30 -29
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
- package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
- package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
- package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
- package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
- package/src/scenarios/dispatchLoop.test.ts +3 -2
- package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
- package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
- package/src/scenarios/distillation-shape.test.ts +4 -4
- package/src/scenarios/distillation-stable-archive.test.ts +6 -6
- package/src/scenarios/distillation-token-budget.test.ts +5 -5
- package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
- package/src/scenarios/egress-audience-binding.test.ts +11 -10
- package/src/scenarios/egress-decision-content-free.test.ts +6 -5
- package/src/scenarios/egress-provenance-shape.test.ts +17 -18
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
- package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
- package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
- package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
- package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
- package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
- package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
- package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
- package/src/scenarios/envelope-truncated.test.ts +19 -17
- package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
- package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
- package/src/scenarios/errors.test.ts +20 -19
- package/src/scenarios/eventOrdering.test.ts +16 -14
- package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
- package/src/scenarios/experimental-tier-shape.test.ts +17 -15
- package/src/scenarios/export-bundle-portability.test.ts +17 -17
- package/src/scenarios/failure-path.test.ts +7 -6
- package/src/scenarios/feedback-capability-shape.test.ts +4 -3
- package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
- package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
- package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
- package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
- package/src/scenarios/feedback-record-and-list.test.ts +2 -1
- package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
- package/src/scenarios/fixtures-gating.test.ts +29 -28
- package/src/scenarios/fixtures-valid.test.ts +16 -15
- package/src/scenarios/form-content-instantiation.test.ts +15 -14
- package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
- package/src/scenarios/fs-path-traversal.test.ts +14 -12
- package/src/scenarios/goal-standing-continuation.test.ts +21 -21
- package/src/scenarios/grpc-transport.test.ts +9 -7
- package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
- package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
- package/src/scenarios/highConcurrency.test.ts +14 -13
- package/src/scenarios/host-callback-declaration.test.ts +8 -7
- package/src/scenarios/http-client-ssrf.test.ts +7 -5
- package/src/scenarios/i18n-negotiation.test.ts +14 -12
- package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
- package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
- package/src/scenarios/idempotency.test.ts +8 -7
- package/src/scenarios/idempotencyRetry.test.ts +13 -11
- package/src/scenarios/identity-owner-shape.test.ts +6 -5
- package/src/scenarios/identity-passthrough.test.ts +4 -3
- package/src/scenarios/interrupt-approval.test.ts +6 -5
- package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
- package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
- package/src/scenarios/interrupt-clarification.test.ts +4 -3
- package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
- package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
- package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
- package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
- package/src/scenarios/interruptRace.test.ts +12 -10
- package/src/scenarios/kv-atomic-increment.test.ts +11 -9
- package/src/scenarios/kv-cas.test.ts +14 -12
- package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
- package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
- package/src/scenarios/localized-content-delivery.test.ts +24 -26
- package/src/scenarios/maliciousManifest.test.ts +10 -8
- package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
- package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
- package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
- package/src/scenarios/mcp-discoverability.test.ts +9 -7
- package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
- package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
- package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
- package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
- package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
- package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
- package/src/scenarios/mcp-stateless-request.test.ts +11 -10
- package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
- package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
- package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
- package/src/scenarios/media-url-inline-cap.test.ts +21 -19
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
- package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
- package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
- package/src/scenarios/memory-attribution-shape.test.ts +4 -3
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
- package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
- package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
- package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
- package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
- package/src/scenarios/memory-degraded-projection.test.ts +10 -9
- package/src/scenarios/memory-injection-budget.test.ts +15 -14
- package/src/scenarios/metric-emission.test.ts +4 -3
- package/src/scenarios/model-capability-insufficient.test.ts +19 -17
- package/src/scenarios/model-capability-substituted.test.ts +20 -18
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
- package/src/scenarios/multi-node-ordering.test.ts +4 -3
- package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
- package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
- package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
- package/src/scenarios/multi-region-idempotency.test.ts +6 -5
- package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
- package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
- package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
- package/src/scenarios/oauth-capability-shape.test.ts +5 -4
- package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
- package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
- package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
- package/src/scenarios/orchestratorDispatch.test.ts +2 -1
- package/src/scenarios/orchestratorTermination.test.ts +2 -1
- package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
- package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
- package/src/scenarios/otel-emission-grpc.test.ts +3 -2
- package/src/scenarios/otel-emission.test.ts +6 -5
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
- package/src/scenarios/otel-trace-propagation.test.ts +2 -1
- package/src/scenarios/owner-subject-echo.test.ts +13 -12
- package/src/scenarios/owner-subject-shape.test.ts +11 -10
- package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
- package/src/scenarios/pack-registry-isolation.test.ts +4 -3
- package/src/scenarios/pack-registry-publish.test.ts +65 -63
- package/src/scenarios/pack-registry.test.ts +38 -36
- package/src/scenarios/pause-resume.test.ts +18 -16
- package/src/scenarios/policies.test.ts +20 -18
- package/src/scenarios/production-backpressure.test.ts +18 -16
- package/src/scenarios/production-retention-expiry.test.ts +8 -6
- package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
- package/src/scenarios/profileDerivation.test.ts +34 -33
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
- package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
- package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
- package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
- package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
- package/src/scenarios/prompt-pack-install.test.ts +14 -12
- package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
- package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
- package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
- package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
- package/src/scenarios/prompt-template-shape.test.ts +30 -28
- package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
- package/src/scenarios/protocol-versions-array.test.ts +10 -9
- package/src/scenarios/provider-usage.test.ts +17 -15
- package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
- package/src/scenarios/purpose-propagation.test.ts +23 -21
- package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
- package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
- package/src/scenarios/rate-limit-envelope.test.ts +6 -5
- package/src/scenarios/redaction.test.ts +13 -11
- package/src/scenarios/redactionAdversarial.test.ts +11 -9
- package/src/scenarios/registry-public.test.ts +12 -11
- package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
- package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
- package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
- package/src/scenarios/replay-fork.test.ts +20 -19
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
- package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
- package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
- package/src/scenarios/replay-retention-expiry.test.ts +11 -9
- package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
- package/src/scenarios/replayDeterminism.test.ts +13 -12
- package/src/scenarios/requirement-ledger.test.ts +15 -14
- package/src/scenarios/restart-during-run.test.ts +3 -2
- package/src/scenarios/route-coverage.test.ts +20 -19
- package/src/scenarios/run-diff.test.ts +22 -20
- package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
- package/src/scenarios/run-transport-economy.test.ts +13 -11
- package/src/scenarios/runner-ledger.test.ts +17 -16
- package/src/scenarios/runs-lifecycle.test.ts +7 -6
- package/src/scenarios/runtime-capabilities.test.ts +12 -10
- package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
- package/src/scenarios/runtime-requires-shape.test.ts +7 -6
- package/src/scenarios/safefetch-behavior.test.ts +22 -21
- package/src/scenarios/safefetch-live-audit.test.ts +14 -13
- package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
- package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
- package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
- package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
- package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
- package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
- package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
- package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
- package/src/scenarios/self-hosted-runner.test.ts +26 -24
- package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
- package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
- package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
- package/src/scenarios/sql-injection-rejection.test.ts +8 -6
- package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
- package/src/scenarios/staleClaim.test.ts +5 -4
- package/src/scenarios/stream-modes-buffer.test.ts +8 -7
- package/src/scenarios/stream-modes-mixed.test.ts +10 -9
- package/src/scenarios/stream-modes.test.ts +12 -11
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
- package/src/scenarios/stream-text-fixture.test.ts +14 -13
- package/src/scenarios/streamReconnect.test.ts +13 -11
- package/src/scenarios/strict-behavior-gate.test.ts +9 -8
- package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
- package/src/scenarios/subrun-approval-gate.test.ts +3 -3
- package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
- package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
- package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
- package/src/scenarios/subworkflow.test.ts +10 -9
- package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/table-cursor-pagination.test.ts +8 -6
- package/src/scenarios/table-schema-enforcement.test.ts +7 -5
- package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
- package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
- package/src/scenarios/tool-catalog-projection.test.ts +11 -9
- package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
- package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
- package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
- package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
- package/src/scenarios/tool-hooks-shape.test.ts +3 -3
- package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
- package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
- package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
- package/src/scenarios/trigger-ingestion.test.ts +19 -17
- package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
- package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
- package/src/scenarios/verifier-gating.test.ts +8 -6
- package/src/scenarios/version-fold.test.ts +9 -8
- package/src/scenarios/version-negotiation.test.ts +12 -11
- package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
- package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
- package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
- package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
- package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
- package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
- package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
- package/src/scenarios/wasm-pack-load.test.ts +4 -3
- package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
- package/src/scenarios/webhook-negative.test.ts +11 -9
- package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
- package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
- package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
- package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
- package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
- package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
- package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
- package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
- package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
- package/src/scenarios/workflow-variable-format.test.ts +24 -24
- package/src/scenarios/workload-identity-behavior.test.ts +15 -13
- package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
- package/src/scenarios/workspace-behavior.test.ts +19 -18
- package/src/scenarios/workspace-capability-shape.test.ts +3 -2
- package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
- package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
- package/src/setup.ts +4 -2
- package/vitest.config.ts +5 -1
- package/api/.redocly.lint-ignore.yaml +0 -22
- package/api/asyncapi.yaml +0 -834
- package/api/grpc/openwop.proto +0 -251
- package/api/openapi.yaml +0 -2693
- package/api/redocly.yaml +0 -23
- package/schemas/README.md +0 -144
- package/schemas/a2a-task-state.schema.json +0 -78
- package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
- package/schemas/agent-deployment-transition.schema.json +0 -49
- package/schemas/agent-deployment.schema.json +0 -54
- package/schemas/agent-eval-suite.schema.json +0 -140
- package/schemas/agent-inventory-response.schema.json +0 -115
- package/schemas/agent-manifest.schema.json +0 -156
- package/schemas/agent-org-chart.schema.json +0 -82
- package/schemas/agent-ref.schema.json +0 -63
- package/schemas/agent-roster-entry.schema.json +0 -81
- package/schemas/agent-roster-response.schema.json +0 -21
- package/schemas/ai-envelope.schema.json +0 -134
- package/schemas/annotation-create.schema.json +0 -37
- package/schemas/annotation.schema.json +0 -56
- package/schemas/artifact-type-pack-manifest.schema.json +0 -244
- package/schemas/audit-verify-result.schema.json +0 -90
- package/schemas/budget-policy.schema.json +0 -18
- package/schemas/capabilities.schema.json +0 -4124
- package/schemas/certification-bundle-v2.schema.json +0 -118
- package/schemas/channel-presence-payload.schema.json +0 -41
- package/schemas/channel-written-payload.schema.json +0 -55
- package/schemas/chat-card-pack-manifest.schema.json +0 -253
- package/schemas/compact-tool-descriptor.schema.json +0 -51
- package/schemas/compensation-policy.schema.json +0 -64
- package/schemas/conformance-certification-bundle.schema.json +0 -86
- package/schemas/connection-pack-manifest.schema.json +0 -353
- package/schemas/conversation-event.schema.json +0 -168
- package/schemas/conversation-turn.schema.json +0 -117
- package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
- package/schemas/credential-provenance.schema.json +0 -18
- package/schemas/credential-reference.schema.json +0 -21
- package/schemas/debug-bundle.schema.json +0 -196
- package/schemas/dispatch-config.schema.json +0 -112
- package/schemas/envelopes/clarification.request.schema.json +0 -52
- package/schemas/envelopes/error.schema.json +0 -30
- package/schemas/envelopes/media.audio.schema.json +0 -38
- package/schemas/envelopes/media.file.schema.json +0 -37
- package/schemas/envelopes/media.image.schema.json +0 -33
- package/schemas/envelopes/schema.request.schema.json +0 -26
- package/schemas/envelopes/schema.response.schema.json +0 -22
- package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
- package/schemas/error-envelope.schema.json +0 -25
- package/schemas/eval-summary.schema.json +0 -92
- package/schemas/export-bundle.schema.json +0 -66
- package/schemas/form-content-pack-manifest.schema.json +0 -243
- package/schemas/frontend-plugin-manifest.schema.json +0 -109
- package/schemas/goal.schema.json +0 -104
- package/schemas/heartbeat-evaluated.schema.json +0 -14
- package/schemas/heartbeat-state-changed.schema.json +0 -14
- package/schemas/localized-content-language-settings.schema.json +0 -26
- package/schemas/localized-content-page-response.schema.json +0 -60
- package/schemas/localized-content-page.schema.json +0 -62
- package/schemas/localized-content-section.schema.json +0 -51
- package/schemas/memory-entry.schema.json +0 -36
- package/schemas/memory-list-options.schema.json +0 -37
- package/schemas/node-pack-manifest.schema.json +0 -654
- package/schemas/orchestrator-decision.schema.json +0 -90
- package/schemas/org-chart-responsibility-view.schema.json +0 -26
- package/schemas/pack-lockfile.schema.json +0 -108
- package/schemas/prompt-kind.schema.json +0 -8
- package/schemas/prompt-pack-manifest.schema.json +0 -117
- package/schemas/prompt-ref.schema.json +0 -40
- package/schemas/prompt-template.schema.json +0 -149
- package/schemas/proposal.schema.json +0 -84
- package/schemas/registry-version-manifest.schema.json +0 -208
- package/schemas/residency.schema.json +0 -16
- package/schemas/run-ancestry-response.schema.json +0 -54
- package/schemas/run-diff-response.schema.json +0 -64
- package/schemas/run-event-payloads.schema.json +0 -4452
- package/schemas/run-event.schema.json +0 -211
- package/schemas/run-options.schema.json +0 -80
- package/schemas/run-orchestrator-decided-event.schema.json +0 -20
- package/schemas/run-snapshot.schema.json +0 -148
- package/schemas/security-advisory.schema.json +0 -109
- package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
- package/schemas/self-hosted-runner-registration.schema.json +0 -53
- package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
- package/schemas/subject.schema.json +0 -56
- package/schemas/suspend-request.schema.json +0 -207
- package/schemas/tool-descriptor.schema.json +0 -63
- package/schemas/trigger-event.schema.json +0 -222
- package/schemas/trigger-subscription-registration.schema.json +0 -67
- package/schemas/trigger-subscription.schema.json +0 -26
- package/schemas/ui-plugin-message.schema.json +0 -90
- package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
- package/schemas/workflow-definition.schema.json +0 -850
- package/schemas/workload-identity.schema.json +0 -79
- package/schemas/workspace-file-create.schema.json +0 -20
- package/schemas/workspace-file.schema.json +0 -39
|
@@ -47,6 +47,8 @@ import { SCHEMAS_DIR, FIXTURES_DIR } from '../lib/paths.js';
|
|
|
47
47
|
import { driver } from '../lib/driver.js';
|
|
48
48
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
49
49
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
50
|
+
import { req } from '../lib/requirement-ids.js';
|
|
51
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
50
52
|
|
|
51
53
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'connection-pack-manifest.schema.json');
|
|
52
54
|
const APIHOSTS_FIXTURE = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-apihosts-valid.json');
|
|
@@ -90,7 +92,7 @@ describe('category: connection-pack apiHosts — schema shape (RFC 0120 §A; inv
|
|
|
90
92
|
it('positive: an openapi-reach provider declaring apiHosts validates', () => {
|
|
91
93
|
expect(
|
|
92
94
|
validate(apiHostsFixture()),
|
|
93
|
-
`connection-packs.md §Manifest item 10: a well-formed apiHosts allow-list MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
95
|
+
req('openwop.it.connection-pack-apihosts.positive-an-openapi-reach-provider-declaring-apihosts-validates', 'RFC 0120', `connection-packs.md §Manifest item 10: a well-formed apiHosts allow-list MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
94
96
|
).toBe(true);
|
|
95
97
|
});
|
|
96
98
|
|
|
@@ -100,16 +102,16 @@ describe('category: connection-pack apiHosts — schema shape (RFC 0120 §A; inv
|
|
|
100
102
|
const errs = failsWith(m, 'required');
|
|
101
103
|
expect(
|
|
102
104
|
errs.some((e) => (e.params as { missingProperty?: string }).missingProperty === 'apiHosts'),
|
|
103
|
-
'connection-packs.md §Manifest item 13: when reach is openapi, apiHosts is REQUIRED (the provider-level allOf)',
|
|
105
|
+
req('openwop.it.connection-pack-apihosts.conditional-must-item-13-a-allof-an-openapi-reach-provider-that-omits-apihosts-i', 'RFC 0120', 'connection-packs.md §Manifest item 13: when reach is openapi, apiHosts is REQUIRED (the provider-level allOf)'),
|
|
104
106
|
).toBe(true);
|
|
105
107
|
});
|
|
106
108
|
|
|
107
109
|
it('omission OK off the conditional: an mcp-reach provider without apiHosts validates', () => {
|
|
108
110
|
const m = mcpFixture();
|
|
109
|
-
expect(m.provider.apiHosts, 'precondition: the github fixture is mcp-reach and declares no apiHosts').toBeUndefined();
|
|
111
|
+
expect(m.provider.apiHosts, req('openwop.it.connection-pack-apihosts.omission-ok-off-the-conditional-an-mcp-reach-provider-without-apihosts-validates', 'RFC 0120', 'precondition: the github fixture is mcp-reach and declares no apiHosts')).toBeUndefined();
|
|
110
112
|
expect(
|
|
111
113
|
validate(m),
|
|
112
|
-
`connection-packs.md §Manifest item 13: a non-openapi provider MAY omit apiHosts. Errors: ${JSON.stringify(validate.errors)}
|
|
114
|
+
req('openwop.it.connection-pack-apihosts.omission-ok-off-the-conditional-an-mcp-reach-provider-without-apihosts-validates', 'RFC 0120', `connection-packs.md §Manifest item 13: a non-openapi provider MAY omit apiHosts. Errors: ${JSON.stringify(validate.errors)}`),
|
|
113
115
|
).toBe(true);
|
|
114
116
|
});
|
|
115
117
|
|
|
@@ -120,7 +122,7 @@ describe('category: connection-pack apiHosts — schema shape (RFC 0120 §A; inv
|
|
|
120
122
|
const errs = failsWith(m, 'pattern');
|
|
121
123
|
expect(
|
|
122
124
|
errs.length,
|
|
123
|
-
`connection-packs.md §Manifest item 11: "${bad}" MUST be rejected — apiHosts entries are bare, lowercase, alphabetic-TLD registrable hostnames (connection_pack_invalid_api_host)
|
|
125
|
+
req('openwop.it.connection-pack-apihosts.entry-shape-item-11-ipv4-literal-wildcard-port-single-label-uppercase-entries-ar', 'RFC 0120', `connection-packs.md §Manifest item 11: "${bad}" MUST be rejected — apiHosts entries are bare, lowercase, alphabetic-TLD registrable hostnames (connection_pack_invalid_api_host)`),
|
|
124
126
|
).toBeGreaterThan(0);
|
|
125
127
|
}
|
|
126
128
|
});
|
|
@@ -128,16 +130,16 @@ describe('category: connection-pack apiHosts — schema shape (RFC 0120 §A; inv
|
|
|
128
130
|
|
|
129
131
|
describe('category: connection-pack apiHosts — matching rule (RFC 0120 item 10; invariant connection-pack-egress-host-bound)', () => {
|
|
130
132
|
it('permits the entry host and its subdomains (eTLD+1 floor)', () => {
|
|
131
|
-
expect(matchesApiHost('facebook.com', 'facebook.com'), 'item 10: a request host equal to the entry matches').toBe(true);
|
|
132
|
-
expect(matchesApiHost('graph.facebook.com', 'facebook.com'), 'item 10: a subdomain of the entry matches (eTLD+1 floor)').toBe(true);
|
|
133
|
-
expect(matchesApiHost('api.example.com', 'example.com'), 'item 10: a subdomain matches').toBe(true);
|
|
133
|
+
expect(matchesApiHost('facebook.com', 'facebook.com'), req('openwop.it.connection-pack-apihosts.permits-the-entry-host-and-its-subdomains-etld-1-floor', 'RFC 0120', 'item 10: a request host equal to the entry matches')).toBe(true);
|
|
134
|
+
expect(matchesApiHost('graph.facebook.com', 'facebook.com'), req('openwop.it.connection-pack-apihosts.permits-the-entry-host-and-its-subdomains-etld-1-floor', 'RFC 0120', 'item 10: a subdomain of the entry matches (eTLD+1 floor)')).toBe(true);
|
|
135
|
+
expect(matchesApiHost('api.example.com', 'example.com'), req('openwop.it.connection-pack-apihosts.permits-the-entry-host-and-its-subdomains-etld-1-floor', 'RFC 0120', 'item 10: a subdomain matches')).toBe(true);
|
|
134
136
|
});
|
|
135
137
|
|
|
136
138
|
it('a pack MAY tighten to an exact host without admitting siblings', () => {
|
|
137
|
-
expect(matchesApiHost('googleads.googleapis.com', 'googleads.googleapis.com'), 'item 10: the tighter exact host matches itself').toBe(true);
|
|
139
|
+
expect(matchesApiHost('googleads.googleapis.com', 'googleads.googleapis.com'), req('openwop.it.connection-pack-apihosts.a-pack-may-tighten-to-an-exact-host-without-admitting-siblings', 'RFC 0120', 'item 10: the tighter exact host matches itself')).toBe(true);
|
|
138
140
|
expect(
|
|
139
141
|
matchesApiHost('bigquery.googleapis.com', 'googleads.googleapis.com'),
|
|
140
|
-
'item 10: a sibling subdomain MUST NOT match a tighter exact-host entry',
|
|
142
|
+
req('openwop.it.connection-pack-apihosts.a-pack-may-tighten-to-an-exact-host-without-admitting-siblings', 'RFC 0120', 'item 10: a sibling subdomain MUST NOT match a tighter exact-host entry'),
|
|
141
143
|
).toBe(false);
|
|
142
144
|
});
|
|
143
145
|
|
|
@@ -145,7 +147,7 @@ describe('category: connection-pack apiHosts — matching rule (RFC 0120 item 10
|
|
|
145
147
|
for (const evil of ['notexample.com', 'evil.com', 'example.com.evil.com', 'myexample.com']) {
|
|
146
148
|
expect(
|
|
147
149
|
matchesApiHost(evil, 'example.com'),
|
|
148
|
-
`item 10: "${evil}" MUST NOT match "example.com" (dot-anchored containment, never a bare substring)
|
|
150
|
+
req('openwop.it.connection-pack-apihosts.no-substring-suffix-prefix-escape-non-matching-hosts-fail-closed', 'RFC 0120', `item 10: "${evil}" MUST NOT match "example.com" (dot-anchored containment, never a bare substring)`),
|
|
149
151
|
).toBe(false);
|
|
150
152
|
}
|
|
151
153
|
});
|
|
@@ -163,10 +165,10 @@ async function gate(): Promise<boolean> {
|
|
|
163
165
|
|
|
164
166
|
describe('connection-pack apiHosts — behavioral egress allow-list (RFC 0120 item 10; capability-gated)', () => {
|
|
165
167
|
it('permits a credential-bearing egress to an apiHosts match; fails closed otherwise (no substring escape)', async () => {
|
|
166
|
-
if (!(await gate())) return;
|
|
168
|
+
if (!(await gate())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await gate())` returned early');
|
|
167
169
|
|
|
168
170
|
const install = await driver.post('/v1/host/sample/connection-packs/install', { manifest: apiHostsFixture() });
|
|
169
|
-
if (install.status === 404 || install.status === 403) return; // seam unwired — soft-skip
|
|
171
|
+
if (install.status === 404 || install.status === 403) return softSkip('blocked', 'precondition not met — `install.status === 404 || install.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
170
172
|
|
|
171
173
|
const probe = async (requestHost: string): Promise<EgressResult | undefined> => {
|
|
172
174
|
const res = await driver.post('/v1/host/sample/connection-packs/egress-check', {
|
|
@@ -178,18 +180,18 @@ describe('connection-pack apiHosts — behavioral egress allow-list (RFC 0120 it
|
|
|
178
180
|
};
|
|
179
181
|
|
|
180
182
|
const allowed = await probe('graph.facebook.com');
|
|
181
|
-
if (allowed === undefined) return; // soft-skip
|
|
183
|
+
if (allowed === undefined) return softSkip('blocked', 'precondition not met — `allowed === undefined` returned early (soft-skip) (seam, prior step, or fixture unavailable)'); // soft-skip
|
|
182
184
|
expect(
|
|
183
185
|
allowed.allowed,
|
|
184
|
-
|
|
186
|
+
req('openwop.it.connection-pack-apihosts.permits-a-credential-bearing-egress-to-an-apihosts-match-fails-closed-otherwise', 'connection-packs.md §Manifest item 10', 'a credential-bearing egress to a host matching apiHosts MUST be permitted'),
|
|
185
187
|
).toBe(true);
|
|
186
188
|
|
|
187
189
|
for (const evil of ['evil.com', 'notfacebook.com', 'facebook.com.evil.com']) {
|
|
188
190
|
const denied = await probe(evil);
|
|
189
|
-
if (denied === undefined) return; // soft-skip
|
|
191
|
+
if (denied === undefined) return softSkip('blocked', 'precondition not met — `denied === undefined` returned early (soft-skip) (seam, prior step, or fixture unavailable)'); // soft-skip
|
|
190
192
|
expect(
|
|
191
193
|
denied.allowed,
|
|
192
|
-
|
|
194
|
+
req('openwop.it.connection-pack-apihosts.permits-a-credential-bearing-egress-to-an-apihosts-match-fails-closed-otherwise', 'connection-packs.md §Manifest item 10', `egress to "${evil}" (no apiHosts match) MUST fail closed — no credential sent`),
|
|
193
195
|
).toBe(false);
|
|
194
196
|
}
|
|
195
197
|
});
|
|
@@ -42,6 +42,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
42
42
|
import addFormats from 'ajv-formats';
|
|
43
43
|
import type { ErrorObject } from 'ajv';
|
|
44
44
|
import { SCHEMAS_DIR, FIXTURES_DIR } from '../lib/paths.js';
|
|
45
|
+
import { req } from '../lib/requirement-ids.js';
|
|
45
46
|
|
|
46
47
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'connection-pack-manifest.schema.json');
|
|
47
48
|
const FIXTURE_PATH = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-github.json');
|
|
@@ -69,7 +70,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
69
70
|
it('positive: the connection-pack-github fixture validates cleanly', () => {
|
|
70
71
|
expect(
|
|
71
72
|
validate(fixture()),
|
|
72
|
-
`connection-packs.md §Manifest clause 1: a well-formed kind:"connection" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
73
|
+
req('openwop.it.connection-pack-manifest-valid.positive-the-connection-pack-github-fixture-validates-cleanly', 'connection-packs.md', `connection-packs.md §Manifest clause 1: a well-formed kind:"connection" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
73
74
|
).toBe(true);
|
|
74
75
|
});
|
|
75
76
|
|
|
@@ -78,10 +79,10 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
78
79
|
properties?: Record<string, { properties?: Record<string, unknown>; required?: string[] }>;
|
|
79
80
|
};
|
|
80
81
|
const connections = caps.properties?.connections;
|
|
81
|
-
expect(connections, 'capabilities.md §connections — the connections block MUST be declared').toBeDefined();
|
|
82
|
+
expect(connections, req('openwop.it.connection-pack-manifest-valid.capabilities-schema-json-declares-connections-packssupported-rfc-0095-c', 'RFC 0095 §C', 'capabilities.md §connections — the connections block MUST be declared')).toBeDefined();
|
|
82
83
|
expect(
|
|
83
84
|
connections?.properties?.packsSupported,
|
|
84
|
-
'RFC 0095 §C — connections.packsSupported MUST be declared',
|
|
85
|
+
req('openwop.it.connection-pack-manifest-valid.capabilities-schema-json-declares-connections-packssupported-rfc-0095-c', 'RFC 0095 §C', 'RFC 0095 §C — connections.packsSupported MUST be declared'),
|
|
85
86
|
).toBeDefined();
|
|
86
87
|
});
|
|
87
88
|
|
|
@@ -90,7 +91,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
90
91
|
const errs = failsWith(m, 'const');
|
|
91
92
|
expect(
|
|
92
93
|
errs.length,
|
|
93
|
-
'connection-packs.md §Manifest clause 1: kind MUST be the const "connection"',
|
|
94
|
+
req('openwop.it.connection-pack-manifest-valid.negative-the-kind-discriminator-routes-other-kinds-away-kind-node-rejected', 'connection-packs.md', 'connection-packs.md §Manifest clause 1: kind MUST be the const "connection"'),
|
|
94
95
|
).toBeGreaterThan(0);
|
|
95
96
|
});
|
|
96
97
|
|
|
@@ -102,7 +103,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
102
103
|
const errs = failsWith(m, 'additionalProperties');
|
|
103
104
|
expect(
|
|
104
105
|
errs.some((e) => (e.params as { additionalProperty?: string }).additionalProperty === 'nodes'),
|
|
105
|
-
'node-packs.md §"Pack kinds": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)',
|
|
106
|
+
req('openwop.it.connection-pack-manifest-valid.negative-a-manifest-mixing-provider-and-nodes-is-rejected-pack-kind-invalid-at-t', 'connection-packs.md', 'node-packs.md §"Pack kinds": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)'),
|
|
106
107
|
).toBe(true);
|
|
107
108
|
});
|
|
108
109
|
|
|
@@ -112,7 +113,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
112
113
|
const errs = failsWith(m, 'pattern');
|
|
113
114
|
expect(
|
|
114
115
|
errs.length,
|
|
115
|
-
'connection-packs.md §Manifest clause 3: auth endpoints MUST be absolute https:// URLs',
|
|
116
|
+
req('openwop.it.connection-pack-manifest-valid.negative-a-non-https-token-endpoint-is-rejected-clause-3', 'connection-packs.md', 'connection-packs.md §Manifest clause 3: auth endpoints MUST be absolute https:// URLs'),
|
|
116
117
|
).toBeGreaterThan(0);
|
|
117
118
|
});
|
|
118
119
|
|
|
@@ -120,7 +121,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
120
121
|
const m = { ...fixture(), version: '1.0.0-alpha.1' };
|
|
121
122
|
expect(
|
|
122
123
|
validate(m),
|
|
123
|
-
`connection-packs.md §Manifest clause 6: prerelease ordering is resolution-time SemVer §11, not manifest shape. Errors: ${JSON.stringify(validate.errors)}
|
|
124
|
+
req('openwop.it.connection-pack-manifest-valid.positive-a-semver-prerelease-version-is-schema-valid-precedence-is-a-host-concer', 'connection-packs.md', `connection-packs.md §Manifest clause 6: prerelease ordering is resolution-time SemVer §11, not manifest shape. Errors: ${JSON.stringify(validate.errors)}`),
|
|
124
125
|
).toBe(true);
|
|
125
126
|
});
|
|
126
127
|
|
|
@@ -130,16 +131,16 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
130
131
|
m.provider.vendor = 'Google';
|
|
131
132
|
expect(
|
|
132
133
|
validate(m),
|
|
133
|
-
`connection-packs.md §Manifest clause 16 (RFC 0123): a string provider.vendor MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
134
|
+
req('openwop.it.connection-pack-manifest-valid.positive-a-provider-vendor-string-validates-rfc-0123', 'RFC 0123', `connection-packs.md §Manifest clause 16 (RFC 0123): a string provider.vendor MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
134
135
|
).toBe(true);
|
|
135
136
|
});
|
|
136
137
|
|
|
137
138
|
it('positive: a manifest OMITTING provider.vendor still validates (back-compat, RFC 0123)', () => {
|
|
138
139
|
const m = fixture();
|
|
139
|
-
expect('vendor' in m.provider, 'the base fixture omits vendor').toBe(false);
|
|
140
|
+
expect('vendor' in m.provider, req('openwop.it.connection-pack-manifest-valid.positive-a-manifest-omitting-provider-vendor-still-validates-back-compat-rfc-012', 'RFC 0123', 'the base fixture omits vendor')).toBe(false);
|
|
140
141
|
expect(
|
|
141
142
|
validate(m),
|
|
142
|
-
`connection-packs.md §Manifest clause 16 (RFC 0123): vendor is OPTIONAL — a manifest without it MUST remain valid. Errors: ${JSON.stringify(validate.errors)}
|
|
143
|
+
req('openwop.it.connection-pack-manifest-valid.positive-a-manifest-omitting-provider-vendor-still-validates-back-compat-rfc-012', 'RFC 0123', `connection-packs.md §Manifest clause 16 (RFC 0123): vendor is OPTIONAL — a manifest without it MUST remain valid. Errors: ${JSON.stringify(validate.errors)}`),
|
|
143
144
|
).toBe(true);
|
|
144
145
|
});
|
|
145
146
|
|
|
@@ -149,7 +150,7 @@ describe('category: connection-pack manifest validation (RFC 0095 §A)', () => {
|
|
|
149
150
|
const errs = failsWith(m, 'type');
|
|
150
151
|
expect(
|
|
151
152
|
errs.some((e) => e.instancePath === '/provider/vendor'),
|
|
152
|
-
'connection-packs.md §Manifest clause 16 (RFC 0123): provider.vendor MUST be a string — an array MUST be rejected',
|
|
153
|
+
req('openwop.it.connection-pack-manifest-valid.negative-a-non-string-provider-vendor-is-rejected-rfc-0123', 'RFC 0123', 'connection-packs.md §Manifest clause 16 (RFC 0123): provider.vendor MUST be a string — an array MUST be rejected'),
|
|
153
154
|
).toBe(true);
|
|
154
155
|
});
|
|
155
156
|
});
|
|
@@ -40,6 +40,8 @@ import { SCHEMAS_DIR, FIXTURES_DIR } from '../lib/paths.js';
|
|
|
40
40
|
import { driver } from '../lib/driver.js';
|
|
41
41
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
42
42
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
43
|
+
import { req } from '../lib/requirement-ids.js';
|
|
44
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
43
45
|
|
|
44
46
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'connection-pack-manifest.schema.json');
|
|
45
47
|
const FIXTURE_PATH = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-github.json');
|
|
@@ -80,7 +82,7 @@ describe('connection-pack-no-credential-material: schema layer (always-on, serve
|
|
|
80
82
|
for (const [where, m] of [['root', atRoot], ['provider', atProvider], ['provider.auth', atAuth]] as const) {
|
|
81
83
|
expect(
|
|
82
84
|
validate(m),
|
|
83
|
-
`SECURITY invariant connection-pack-no-credential-material — a property named "${name}" at ${where} MUST NOT validate (additionalProperties:false)
|
|
85
|
+
req('openwop.it.connection-pack-no-credential-material.every-blocklisted-property-name-is-schema-rejected-at-the-root-provider-and-auth', 'connection-packs.md', `SECURITY invariant connection-pack-no-credential-material — a property named "${name}" at ${where} MUST NOT validate (additionalProperties:false)`),
|
|
84
86
|
).toBe(false);
|
|
85
87
|
}
|
|
86
88
|
}
|
|
@@ -90,11 +92,11 @@ describe('connection-pack-no-credential-material: schema layer (always-on, serve
|
|
|
90
92
|
const m = fixture();
|
|
91
93
|
expect(
|
|
92
94
|
typeof (m.provider.auth.endpoints as Record<string, string>).token,
|
|
93
|
-
'fixture sanity — the github fixture declares the token endpoint',
|
|
95
|
+
req('openwop.it.connection-pack-no-credential-material.the-exemption-provider-auth-endpoints-token-the-token-endpoint-url-is-valid', 'connection-packs.md', 'fixture sanity — the github fixture declares the token endpoint'),
|
|
94
96
|
).toBe('string');
|
|
95
97
|
expect(
|
|
96
98
|
validate(m),
|
|
97
|
-
`connection-packs.md §Manifest clause 2 — the property named "token" at exactly provider.auth.endpoints.token is the OAuth token-endpoint URL and MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
99
|
+
req('openwop.it.connection-pack-no-credential-material.the-exemption-provider-auth-endpoints-token-the-token-endpoint-url-is-valid', 'connection-packs.md', `connection-packs.md §Manifest clause 2 — the property named "token" at exactly provider.auth.endpoints.token is the OAuth token-endpoint URL and MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
98
100
|
).toBe(true);
|
|
99
101
|
});
|
|
100
102
|
});
|
|
@@ -107,16 +109,16 @@ describe('connection-pack-no-credential-material: specific rejection code (capab
|
|
|
107
109
|
const leaky = fixture();
|
|
108
110
|
(leaky.provider.auth as Record<string, unknown>).clientSecret = 'ghs_conformance_canary';
|
|
109
111
|
const res = await driver.post('/v1/host/sample/connection-packs/install', { manifest: leaky });
|
|
110
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
112
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
111
113
|
|
|
112
114
|
const body = res.json as { installed?: boolean; errors?: Array<{ code?: string }> } | undefined;
|
|
113
115
|
expect(
|
|
114
116
|
body?.installed,
|
|
115
|
-
|
|
117
|
+
req('openwop.it.connection-pack-no-credential-material.installing-a-manifest-carrying-clientsecret-is-rejected-with-connection-pack-cre', 'connection-packs.md §Manifest clause 2', 'a manifest carrying credential material MUST NOT install'),
|
|
116
118
|
).toBe(false);
|
|
117
119
|
expect(
|
|
118
120
|
(body?.errors ?? []).some((e) => e.code === 'connection_pack_credential_material'),
|
|
119
|
-
|
|
121
|
+
req('openwop.it.connection-pack-no-credential-material.installing-a-manifest-carrying-clientsecret-is-rejected-with-connection-pack-cre',
|
|
120
122
|
'connection-packs.md §Manifest clause 2',
|
|
121
123
|
'the credential-material scan runs BEFORE generic schema validation — the SPECIFIC code connection_pack_credential_material MUST surface, not a generic shape error',
|
|
122
124
|
),
|
|
@@ -23,6 +23,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
23
23
|
import addFormats from 'ajv-formats';
|
|
24
24
|
import type { ErrorObject } from 'ajv';
|
|
25
25
|
import { SCHEMAS_DIR, FIXTURES_DIR } from '../lib/paths.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
27
|
|
|
27
28
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'connection-pack-manifest.schema.json');
|
|
28
29
|
const FIXTURE_PATH = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-github.json');
|
|
@@ -60,7 +61,7 @@ describe('connection-pack-reach-exclusive (RFC 0095 §B.5)', () => {
|
|
|
60
61
|
for (const reach of [MCP, OPENAPI, INTEGRATION]) {
|
|
61
62
|
expect(
|
|
62
63
|
validate(withReach(reach)),
|
|
63
|
-
`connection-packs.md §Manifest clause 5: a single reach mode (${Object.keys(reach)[0]}) MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
64
|
+
req('openwop.it.connection-pack-reach-exclusive.positive-each-reach-mode-validates-alone', 'connection-packs.md', `connection-packs.md §Manifest clause 5: a single reach mode (${Object.keys(reach)[0]}) MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
64
65
|
).toBe(true);
|
|
65
66
|
}
|
|
66
67
|
});
|
|
@@ -69,7 +70,7 @@ describe('connection-pack-reach-exclusive (RFC 0095 §B.5)', () => {
|
|
|
69
70
|
const errs = failsWith(withReach({ ...MCP, ...OPENAPI }), 'maxProperties');
|
|
70
71
|
expect(
|
|
71
72
|
errs.length,
|
|
72
|
-
'connection-packs.md §Manifest clause 5: reach MUST specify exactly one of mcp/openapi/integration',
|
|
73
|
+
req('openwop.it.connection-pack-reach-exclusive.negative-two-reach-modes-are-rejected-maxproperties-1', 'connection-packs.md', 'connection-packs.md §Manifest clause 5: reach MUST specify exactly one of mcp/openapi/integration'),
|
|
73
74
|
).toBeGreaterThan(0);
|
|
74
75
|
});
|
|
75
76
|
|
|
@@ -77,7 +78,7 @@ describe('connection-pack-reach-exclusive (RFC 0095 §B.5)', () => {
|
|
|
77
78
|
const errs = failsWith(withReach({}), 'minProperties');
|
|
78
79
|
expect(
|
|
79
80
|
errs.length,
|
|
80
|
-
'connection-packs.md §Manifest clause 5: reach MUST declare a mode — an empty object is invalid',
|
|
81
|
+
req('openwop.it.connection-pack-reach-exclusive.negative-an-empty-reach-is-rejected-minproperties-1', 'connection-packs.md', 'connection-packs.md §Manifest clause 5: reach MUST declare a mode — an empty object is invalid'),
|
|
81
82
|
).toBeGreaterThan(0);
|
|
82
83
|
});
|
|
83
84
|
|
|
@@ -85,7 +86,7 @@ describe('connection-pack-reach-exclusive (RFC 0095 §B.5)', () => {
|
|
|
85
86
|
const errs = failsWith(withReach({ grpc: { url: 'https://example.com' } }), 'additionalProperties');
|
|
86
87
|
expect(
|
|
87
88
|
errs.some((e) => (e.params as { additionalProperty?: string }).additionalProperty === 'grpc'),
|
|
88
|
-
'connection-packs.md §Manifest clause 5: the reach vocabulary is closed (mcp | openapi | integration)',
|
|
89
|
+
req('openwop.it.connection-pack-reach-exclusive.negative-an-unknown-reach-mode-is-rejected-additionalproperties-false', 'connection-packs.md', 'connection-packs.md §Manifest clause 5: the reach vocabulary is closed (mcp | openapi | integration)'),
|
|
89
90
|
).toBe(true);
|
|
90
91
|
});
|
|
91
92
|
});
|
|
@@ -30,6 +30,8 @@ import { FIXTURES_DIR } from '../lib/paths.js';
|
|
|
30
30
|
import { driver } from '../lib/driver.js';
|
|
31
31
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
32
32
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
33
35
|
|
|
34
36
|
const FIXTURE_PATH = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-github.json');
|
|
35
37
|
|
|
@@ -54,13 +56,13 @@ describe('connection-pack-write-reconsent (RFC 0095 §B.4)', () => {
|
|
|
54
56
|
provider: 'github',
|
|
55
57
|
requested: ['read', 'write'],
|
|
56
58
|
});
|
|
57
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
59
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
58
60
|
|
|
59
61
|
const plan = res.json as ConsentPlan | undefined;
|
|
60
62
|
const steps = plan?.steps ?? [];
|
|
61
63
|
expect(
|
|
62
64
|
steps.length >= 2,
|
|
63
|
-
|
|
65
|
+
req('openwop.it.connection-pack-write-reconsent.write-scope-groups-are-a-separate-consent-step-never-bundled-into-the-initial-re',
|
|
64
66
|
'connection-packs.md §Manifest clause 4',
|
|
65
67
|
'requesting read + write scope groups MUST plan write as a SEPARATE consent step (≥ 2 steps)',
|
|
66
68
|
),
|
|
@@ -70,7 +72,7 @@ describe('connection-pack-write-reconsent (RFC 0095 §B.4)', () => {
|
|
|
70
72
|
first.includesWrite === true || (first.groups ?? []).some((g) => g.access === 'write');
|
|
71
73
|
expect(
|
|
72
74
|
firstHasWrite,
|
|
73
|
-
|
|
75
|
+
req('openwop.it.connection-pack-write-reconsent.write-scope-groups-are-a-separate-consent-step-never-bundled-into-the-initial-re',
|
|
74
76
|
'connection-packs.md §Manifest clause 4',
|
|
75
77
|
'the INITIAL authorization step MUST NOT bundle write scopes',
|
|
76
78
|
),
|
|
@@ -84,7 +86,7 @@ describe('connection-pack-write-reconsent (RFC 0095 §B.4)', () => {
|
|
|
84
86
|
const roSteps = (readOnly.json as ConsentPlan | undefined)?.steps ?? [];
|
|
85
87
|
expect(
|
|
86
88
|
roSteps.length,
|
|
87
|
-
|
|
89
|
+
req('openwop.it.connection-pack-write-reconsent.write-scope-groups-are-a-separate-consent-step-never-bundled-into-the-initial-re', 'connection-packs.md §Manifest clause 4', 'a read-only request plans a single consent step'),
|
|
88
90
|
).toBe(1);
|
|
89
91
|
}
|
|
90
92
|
});
|
|
@@ -34,6 +34,8 @@ import { FIXTURES_DIR } from '../lib/paths.js';
|
|
|
34
34
|
import { driver } from '../lib/driver.js';
|
|
35
35
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
36
36
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
37
|
+
import { req } from '../lib/requirement-ids.js';
|
|
38
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
37
39
|
|
|
38
40
|
const FIXTURE_PATH = join(FIXTURES_DIR, 'connection-packs', 'connection-pack-github.json');
|
|
39
41
|
|
|
@@ -64,25 +66,25 @@ async function gate(): Promise<boolean> {
|
|
|
64
66
|
|
|
65
67
|
describe('connection-provider-resolution (RFC 0095 §B.6/§B.8)', () => {
|
|
66
68
|
it('an installed pack resolves its provider id; an unknown provider is unresolved', async () => {
|
|
67
|
-
if (!(await gate())) return;
|
|
69
|
+
if (!(await gate())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await gate())` returned early');
|
|
68
70
|
|
|
69
71
|
const install = await driver.post('/v1/host/sample/connection-packs/install', { manifest: fixture() });
|
|
70
|
-
if (install.status === 404 || install.status === 403) return; // seam unwired — soft-skip
|
|
72
|
+
if (install.status === 404 || install.status === 403) return softSkip('blocked', 'precondition not met — `install.status === 404 || install.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
71
73
|
const installed = install.json as InstallResult | undefined;
|
|
72
74
|
expect(
|
|
73
75
|
installed?.installed,
|
|
74
|
-
|
|
76
|
+
req('openwop.it.connection-provider-resolution.an-installed-pack-resolves-its-provider-id-an-unknown-provider-is-unresolved', 'connection-packs.md §Manifest clause 1', 'a well-formed connection pack MUST install'),
|
|
75
77
|
).toBe(true);
|
|
76
78
|
|
|
77
79
|
const hit = await driver.post('/v1/host/sample/connection-packs/resolve', { provider: 'github' });
|
|
78
80
|
const resolved = hit.json as ResolveResult | undefined;
|
|
79
81
|
expect(
|
|
80
82
|
resolved?.resolved,
|
|
81
|
-
|
|
83
|
+
req('openwop.it.connection-provider-resolution.an-installed-pack-resolves-its-provider-id-an-unknown-provider-is-unresolved', 'connection-packs.md §Manifest clause 6', 'provider "github" MUST resolve against the installed pack whose provider.id matches'),
|
|
82
84
|
).toBe(true);
|
|
83
85
|
expect(
|
|
84
86
|
resolved?.source,
|
|
85
|
-
|
|
87
|
+
req('openwop.it.connection-provider-resolution.an-installed-pack-resolves-its-provider-id-an-unknown-provider-is-unresolved', 'connection-packs.md §Manifest clause 6', 'the installed pack is the resolution source'),
|
|
86
88
|
).toBe('pack');
|
|
87
89
|
|
|
88
90
|
const miss = await driver.post('/v1/host/sample/connection-packs/resolve', {
|
|
@@ -91,35 +93,35 @@ describe('connection-provider-resolution (RFC 0095 §B.6/§B.8)', () => {
|
|
|
91
93
|
const unresolved = miss.json as ResolveResult | undefined;
|
|
92
94
|
expect(
|
|
93
95
|
unresolved?.resolved,
|
|
94
|
-
|
|
96
|
+
req('openwop.it.connection-provider-resolution.an-installed-pack-resolves-its-provider-id-an-unknown-provider-is-unresolved', 'connection-packs.md §Manifest clause 6', 'a provider with no installed pack and no built-in MUST NOT resolve'),
|
|
95
97
|
).toBe(false);
|
|
96
98
|
expect(
|
|
97
99
|
unresolved?.code,
|
|
98
|
-
|
|
100
|
+
req('openwop.it.connection-provider-resolution.an-installed-pack-resolves-its-provider-id-an-unknown-provider-is-unresolved', 'connection-packs.md §Manifest clause 6', 'the refusal code MUST be connection_provider_unresolved'),
|
|
99
101
|
).toBe('connection_provider_unresolved');
|
|
100
102
|
});
|
|
101
103
|
|
|
102
104
|
it('an installed prerelease does not outrank a built-in release — conflict surfaces (SemVer §11)', async () => {
|
|
103
|
-
if (!(await gate())) return;
|
|
105
|
+
if (!(await gate())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await gate())` returned early');
|
|
104
106
|
|
|
105
107
|
const prerelease = { ...fixture(), version: '1.0.0-alpha.1' };
|
|
106
108
|
prerelease.provider = { ...prerelease.provider, id: 'conformance-prerelease-probe' };
|
|
107
109
|
const install = await driver.post('/v1/host/sample/connection-packs/install', { manifest: prerelease });
|
|
108
|
-
if (install.status === 404 || install.status === 403) return; // seam unwired — soft-skip
|
|
110
|
+
if (install.status === 404 || install.status === 403) return softSkip('blocked', 'precondition not met — `install.status === 404 || install.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
109
111
|
expect(
|
|
110
112
|
(install.json as InstallResult | undefined)?.installed,
|
|
111
|
-
|
|
113
|
+
req('openwop.it.connection-provider-resolution.an-installed-prerelease-does-not-outrank-a-built-in-release-conflict-surfaces-se', 'connection-packs.md §Manifest clause 1', 'a prerelease-versioned pack is shape-valid and MUST install'),
|
|
112
114
|
).toBe(true);
|
|
113
115
|
|
|
114
116
|
const res = await driver.post('/v1/host/sample/connection-packs/resolve', {
|
|
115
117
|
provider: 'conformance-prerelease-probe',
|
|
116
118
|
simulateBuiltinVersion: '1.0.0',
|
|
117
119
|
});
|
|
118
|
-
if (res.status === 404 || res.status === 403) return; // simulate knob unwired — soft-skip
|
|
120
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (simulate knob unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // simulate knob unwired — soft-skip
|
|
119
121
|
const body = res.json as ResolveResult | undefined;
|
|
120
122
|
expect(
|
|
121
123
|
body?.code,
|
|
122
|
-
|
|
124
|
+
req('openwop.it.connection-provider-resolution.an-installed-prerelease-does-not-outrank-a-built-in-release-conflict-surfaces-se',
|
|
123
125
|
'connection-packs.md §Manifest clause 6',
|
|
124
126
|
'SemVer §11: 1.0.0-alpha.1 < 1.0.0 — the installed pack is NOT greater-or-equal, so the host MUST surface connection_provider_conflict rather than silently choosing',
|
|
125
127
|
),
|
|
@@ -127,16 +129,16 @@ describe('connection-provider-resolution (RFC 0095 §B.6/§B.8)', () => {
|
|
|
127
129
|
});
|
|
128
130
|
|
|
129
131
|
it('rejection isolation: one rejected pack never takes down the install path (§B.8)', async () => {
|
|
130
|
-
if (!(await gate())) return;
|
|
132
|
+
if (!(await gate())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await gate())` returned early');
|
|
131
133
|
|
|
132
134
|
const leaky = fixture();
|
|
133
135
|
leaky.provider = { ...leaky.provider, id: 'conformance-isolation-probe' };
|
|
134
136
|
(leaky.provider.auth as Record<string, unknown>).clientSecret = 'ghs_conformance_canary';
|
|
135
137
|
const bad = await driver.post('/v1/host/sample/connection-packs/install', { manifest: leaky });
|
|
136
|
-
if (bad.status === 404 || bad.status === 403) return; // seam unwired — soft-skip
|
|
138
|
+
if (bad.status === 404 || bad.status === 403) return softSkip('blocked', 'precondition not met — `bad.status === 404 || bad.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
137
139
|
expect(
|
|
138
140
|
(bad.json as InstallResult | undefined)?.installed,
|
|
139
|
-
|
|
141
|
+
req('openwop.it.connection-provider-resolution.rejection-isolation-one-rejected-pack-never-takes-down-the-install-path-b-8', 'connection-packs.md §Manifest clause 2', 'the credential-carrying manifest MUST NOT install'),
|
|
140
142
|
).toBe(false);
|
|
141
143
|
|
|
142
144
|
const good = { ...fixture() };
|
|
@@ -144,7 +146,7 @@ describe('connection-provider-resolution (RFC 0095 §B.6/§B.8)', () => {
|
|
|
144
146
|
const after = await driver.post('/v1/host/sample/connection-packs/install', { manifest: good });
|
|
145
147
|
expect(
|
|
146
148
|
(after.json as InstallResult | undefined)?.installed,
|
|
147
|
-
|
|
149
|
+
req('openwop.it.connection-provider-resolution.rejection-isolation-one-rejected-pack-never-takes-down-the-install-path-b-8',
|
|
148
150
|
'connection-packs.md §Manifest clause 8',
|
|
149
151
|
'a rejected pack means NOT INSTALLED — nothing more; a subsequent valid install MUST succeed',
|
|
150
152
|
),
|
|
@@ -27,6 +27,7 @@ import { join } from 'node:path';
|
|
|
27
27
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
28
28
|
import addFormats from 'ajv-formats';
|
|
29
29
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
30
|
+
import { req } from '../lib/requirement-ids.js';
|
|
30
31
|
|
|
31
32
|
interface SchemaDefs {
|
|
32
33
|
$defs: Record<string, unknown>;
|
|
@@ -82,7 +83,7 @@ describe('category: connector-manifest validity — schema shape (RFC 0045 §A)'
|
|
|
82
83
|
],
|
|
83
84
|
triggers: ['vendor.acme.salesforce.onRecordChange'],
|
|
84
85
|
});
|
|
85
|
-
expect(ok, JSON.stringify(validate.errors)).toBe(true);
|
|
86
|
+
expect(ok, req('openwop.it.connector-manifest-validity.positive-a-well-formed-connector-block-oauth2-auth-validates', 'RFC 0045 §A/§B', JSON.stringify(validate.errors))).toBe(true);
|
|
86
87
|
});
|
|
87
88
|
|
|
88
89
|
it('positive: credential-auth variant validates', () => {
|
|
@@ -92,11 +93,11 @@ describe('category: connector-manifest validity — schema shape (RFC 0045 §A)'
|
|
|
92
93
|
auth: { type: 'credential', key: 'stripe-secret-key', scope: 'workspace' },
|
|
93
94
|
actions: [{ typeId: 'vendor.acme.stripe.charge', displayName: 'Charge' }],
|
|
94
95
|
});
|
|
95
|
-
expect(ok, JSON.stringify(validate.errors)).toBe(true);
|
|
96
|
+
expect(ok, req('openwop.it.connector-manifest-validity.positive-credential-auth-variant-validates', 'RFC 0045 §A/§B', JSON.stringify(validate.errors))).toBe(true);
|
|
96
97
|
});
|
|
97
98
|
|
|
98
99
|
it('negative: connector missing displayName is rejected', () => {
|
|
99
|
-
expect(validate({ id: 'salesforce' })).toBe(false);
|
|
100
|
+
expect(validate({ id: 'salesforce' }), req('openwop.it.connector-manifest-validity.negative-connector-missing-displayname-is-rejected', 'RFC 0045 §A/§B', 'negative: connector missing displayName is rejected')).toBe(false);
|
|
100
101
|
});
|
|
101
102
|
|
|
102
103
|
it('negative: an action missing typeId is rejected', () => {
|
|
@@ -105,7 +106,7 @@ describe('category: connector-manifest validity — schema shape (RFC 0045 §A)'
|
|
|
105
106
|
displayName: 'Salesforce',
|
|
106
107
|
actions: [{ displayName: 'Upsert' }],
|
|
107
108
|
});
|
|
108
|
-
expect(ok).toBe(false);
|
|
109
|
+
expect(ok, req('openwop.it.connector-manifest-validity.negative-an-action-missing-typeid-is-rejected', 'RFC 0045 §A/§B', 'negative: an action missing typeId is rejected')).toBe(false);
|
|
109
110
|
});
|
|
110
111
|
|
|
111
112
|
it('negative: an unknown ConnectorAuth type is rejected', () => {
|
|
@@ -114,7 +115,7 @@ describe('category: connector-manifest validity — schema shape (RFC 0045 §A)'
|
|
|
114
115
|
displayName: 'Salesforce',
|
|
115
116
|
auth: { type: 'basic', user: 'x' },
|
|
116
117
|
});
|
|
117
|
-
expect(ok).toBe(false);
|
|
118
|
+
expect(ok, req('openwop.it.connector-manifest-validity.negative-an-unknown-connectorauth-type-is-rejected', 'RFC 0045 §A/§B', 'negative: an unknown ConnectorAuth type is rejected')).toBe(false);
|
|
118
119
|
});
|
|
119
120
|
});
|
|
120
121
|
|
|
@@ -130,13 +131,13 @@ describe('category: connector-manifest validity — action resolution (RFC 0045
|
|
|
130
131
|
actions: [{ typeId: 'vendor.acme.salesforce.upsert' }, { typeId: 'vendor.acme.salesforce.query' }],
|
|
131
132
|
triggers: ['vendor.acme.salesforce.onRecordChange'],
|
|
132
133
|
});
|
|
133
|
-
expect(unresolved, 'every connector.actions[].typeId + triggers[] MUST resolve to a nodes[].typeId').toEqual([]);
|
|
134
|
+
expect(unresolved, req('openwop.it.connector-manifest-validity.all-action-trigger-typeids-resolve-to-nodes-in-the-same-manifest', 'RFC 0045 §A/§B', 'every connector.actions[].typeId + triggers[] MUST resolve to a nodes[].typeId')).toEqual([]);
|
|
134
135
|
});
|
|
135
136
|
|
|
136
137
|
it('an action typeId not in nodes[] is flagged (connector_action_unresolved)', () => {
|
|
137
138
|
const unresolved = unresolvedReferences(nodeTypeIds, {
|
|
138
139
|
actions: [{ typeId: 'vendor.acme.salesforce.does-not-exist' }],
|
|
139
140
|
});
|
|
140
|
-
expect(unresolved).toContain('vendor.acme.salesforce.does-not-exist');
|
|
141
|
+
expect(unresolved, req('openwop.it.connector-manifest-validity.an-action-typeid-not-in-nodes-is-flagged-connector-action-unresolved', 'RFC 0045 §A/§B', 'an action typeId not in nodes[] is flagged (connector_action_unresolved)')).toContain('vendor.acme.salesforce.does-not-exist');
|
|
141
142
|
});
|
|
142
143
|
});
|