@reventlessdev/reventless-aws 3.0.0-alpha.344 → 3.0.0-alpha.346
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/CHANGELOG.md +36 -0
- package/package.json +15 -12
- package/run-provision-accounts.mjs +3 -0
- package/run-provision-admin.mjs +3 -0
- package/scripts/ProvisionAccounts.res +325 -0
- package/scripts/ProvisionAccounts.res.mjs +337 -0
- package/scripts/ProvisionAdmin.res +275 -0
- package/scripts/ProvisionAdmin.res.mjs +289 -0
- package/scripts/ProvisionCognito.res +149 -0
- package/scripts/ProvisionCognito.res.mjs +98 -0
- package/scripts/ProvisionIdentity.res +84 -14
- package/scripts/ProvisionIdentity.res.mjs +72 -7
- package/scripts/ProvisionProvider.res +104 -0
- package/scripts/ProvisionProvider.res.mjs +123 -0
- package/src/Platform.res +358 -329
- package/src/Platform.res.mjs +24 -12
- package/src/Platform_Casts.res +13 -4
- package/src/Platform_Stack.res +119 -9
- package/src/Platform_Stack.res.mjs +42 -4
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
- package/src/adapter/Api/AppSync_EventsApi.res +12 -14
- package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
- package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
- package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
- package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
- package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
- package/src/adapter/Auth/Auth_Cognito.res +3 -9
- package/src/adapter/Auth/Auth_LoginIdentifier.res +66 -0
- package/src/adapter/Auth/Auth_LoginIdentifier.res.mjs +70 -0
- package/src/adapter/Auth/Auth_SignUpMode.res +78 -0
- package/src/adapter/Auth/Auth_SignUpMode.res.mjs +56 -0
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
- package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
- package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
- package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
- package/src/adapter/Mcp/MCP_Lambda.res +31 -46
- package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
- package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
- package/src/adapter/Postgres/PgConnection.res +6 -5
- package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
- package/src/adapter/Postgres/PgRuntime.res +4 -7
- package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
- package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
- package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
- package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
- package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
- package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
- package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +23 -11
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +5 -1
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
- package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
- package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
- package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
- package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
- package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
- package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
- package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
- package/src/adapter/Task/TaskBucket_S3.res +6 -1
- package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
- package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
- package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
- package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
- package/src/capability/Capability_Messaging.res +4 -5
- package/src/capability/Capability_Messaging_Ses.res +3 -1
- package/src/capability/Capability_ObjectStore_S3.res +1 -7
- package/src/components/Api/AppSync_Adapter.res +80 -109
- package/src/components/Api/AppSync_Adapter.res.mjs +26 -60
- package/src/components/Api/AppSync_SdlDecorate.res +118 -31
- package/src/components/Api/AppSync_SdlDecorate.res.mjs +45 -0
- package/src/components/AutomationSlice_Builder.res +6 -4
- package/src/components/ExtensionPoint_Builder.res +9 -10
- package/src/components/InboundTranslationSlice_Builder.res +7 -8
- package/src/components/OutboundTranslationSlice_Builder.res +14 -8
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
- package/src/components/SideEffectHandler_Single.res +4 -4
- package/src/components/StateViewSlice_Builder.res +6 -4
- package/src/components/StateViewSlice_Builder_Stream.res +6 -4
- package/src/components/Task_Builder_PerBucket.res +10 -11
- package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
- package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
- package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
- package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
- package/src/plugin/stack/Plugin_Stack.res +104 -103
- package/src/util/Util_AlarmSpec.res +2 -1
- package/src/util/Util_AppSync.res +8 -2
- package/src/util/Util_AppSync_Caller.res +15 -14
- package/src/util/Util_Bundle.res +46 -42
- package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
- package/src/util/Util_Cognito_Runtime.res +11 -7
- package/src/util/Util_DeadLetterQueue.res +12 -2
- package/src/util/Util_DynamoDb.res +5 -3
- package/src/util/Util_DynamoDbStream.res +7 -3
- package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
- package/src/util/Util_DynamoDb_Runtime.res +23 -41
- package/src/util/Util_HostUiDomain.res +6 -1
- package/src/util/Util_Kinesis_Runtime.res +10 -11
- package/src/util/Util_Lambda.res +12 -5
- package/src/util/Util_LambdaEnvBudget.res +5 -5
- package/src/util/Util_LambdaLogging.res +1 -2
- package/src/util/Util_LogGroup_Adopting.res +1 -4
- package/src/util/Util_ResourceNaming.res +1 -2
- package/src/util/Util_SNS.res +8 -3
- package/src/util/Util_SNS_FIFO.res +1 -1
- package/src/util/Util_SNS_Runtime.res +11 -10
- package/src/util/Util_SQS.res +4 -2
- package/src/util/Util_SQS_FIFO.res +5 -2
- package/src/util/Util_SQS_Runtime.res +37 -36
- package/src/util/Util_ShellConfig.res +3 -2
- package/src/util/Util_StaticBundle.res +1 -3
- package/src/util/Util_StoreLayout.res +4 -1
- package/tests/AWS_TagsTest.res +16 -5
- package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
- package/tests/AppSync_AdapterTest.res +286 -224
- package/tests/AppSync_AdapterTest.res.mjs +69 -0
- package/tests/AppSync_Resolver_RetryingTest.res +64 -44
- package/tests/AppSync_RetirementNarrowingTest.res +59 -46
- package/tests/AppSync_SdlDecorateTest.res +22 -20
- package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
- package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
- package/tests/Auth_ActiveRoleStoreTest.res +12 -9
- package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
- package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
- package/tests/Auth_CognitoTest.res +31 -46
- package/tests/Auth_LoginIdentifierTest.res +51 -0
- package/tests/Auth_LoginIdentifierTest.res.mjs +51 -0
- package/tests/Auth_SignUpModeTest.res +56 -0
- package/tests/Auth_SignUpModeTest.res.mjs +53 -0
- package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
- package/tests/BakeConvergenceTest.res +22 -25
- package/tests/Capability_MessagingTest.res +28 -12
- package/tests/CommandTopicQueuePolicyTest.res +1 -2
- package/tests/CounterEntryPoint_OpsTest.res +3 -7
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
- package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
- package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
- package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
- package/tests/EventCollectorReadyGateTest.res +5 -4
- package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
- package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
- package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
- package/tests/HandlerFactoryDispatchTest.res +97 -70
- package/tests/MCP_LambdaTest.res +16 -27
- package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
- package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
- package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
- package/tests/PgPipeline_IntegrationTest.res +80 -66
- package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
- package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
- package/tests/PgQueryResolver_LambdaTest.res +41 -24
- package/tests/Platform_AdminScan_OpsTest.res +4 -1
- package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
- package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
- package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
- package/tests/ProvisionAccountsTest.res +142 -0
- package/tests/ProvisionAccountsTest.res.mjs +153 -0
- package/tests/ProvisionAdminTest.res +55 -0
- package/tests/ProvisionAdminTest.res.mjs +66 -0
- package/tests/ProvisionIdentityTest.res +91 -9
- package/tests/ProvisionIdentityTest.res.mjs +66 -1
- package/tests/QueryDbOwnerIndexTableTest.res +6 -4
- package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
- package/tests/QueryInterceptor_LambdaTest.res +11 -13
- package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
- package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
- package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
- package/tests/StateChangeDescriptorParityTest.res +28 -26
- package/tests/StateTopicKeySchemaTest.res +18 -15
- package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
- package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
- package/tests/Upload_ClaimTest.res +3 -3
- package/tests/Util_AwsErrorTest.res +4 -7
- package/tests/Util_BundleDependencyClosureTest.res +15 -3
- package/tests/Util_BundleEsmLoaderTest.res +3 -3
- package/tests/Util_BundleResolveTest.res +4 -6
- package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
- package/tests/Util_DcbMetricsTest.res +6 -6
- package/tests/Util_DynamoDbStreamTest.res +4 -5
- package/tests/Util_DynamoDbTest.res +3 -2
- package/tests/Util_LambdaEnvBudgetTest.res +22 -18
- package/tests/Util_LambdaLoggingTest.res +9 -8
- package/tests/Util_LogGroup_AdoptingTest.res +10 -5
- package/tests/Util_LogRetentionTest.res +6 -2
- package/tests/Util_OwnerScopeEnvTest.res +35 -8
- package/tests/Util_OwnerScopeEnvTest.res.mjs +13 -0
- package/tests/Util_SQS_RuntimeTest.res +5 -7
- package/tests/Util_ShellConfigTest.res +7 -17
- package/tests/Util_StaticBundleTest.res +3 -8
- package/tests/Util_StoreLayoutTest.res +17 -12
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
- package/tests/integration/DcbIntegrationHarness.res +8 -8
- package/tests/integration/EpCompositeSlice.res +16 -8
- package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
- package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
- package/tests/integration/SvsTestSlice_Projection.res +1 -3
- package/tests/util/Util_AlarmSpecTest.res +62 -49
|
@@ -28,17 +28,21 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
|
|
|
28
28
|
testSync("adds the Cognito group directive to all mutation fields", () => {
|
|
29
29
|
let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="Admin")
|
|
30
30
|
let parts = decodeFragment(augmented)
|
|
31
|
-
parts.mutations->Array.forEach(
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
parts.mutations->Array.forEach(
|
|
32
|
+
field => {
|
|
33
|
+
expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
34
|
+
},
|
|
35
|
+
)
|
|
34
36
|
})
|
|
35
37
|
|
|
36
38
|
testSync("adds the Cognito group directive to all query fields", () => {
|
|
37
39
|
let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="Admin")
|
|
38
40
|
let parts = decodeFragment(augmented)
|
|
39
|
-
parts.queries->Array.forEach(
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
parts.queries->Array.forEach(
|
|
42
|
+
field => {
|
|
43
|
+
expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
44
|
+
},
|
|
45
|
+
)
|
|
42
46
|
})
|
|
43
47
|
|
|
44
48
|
testSync("preserves type definitions unchanged", () => {
|
|
@@ -51,9 +55,11 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
|
|
|
51
55
|
testSync("uses specified group name", () => {
|
|
52
56
|
let augmented = AppSync_Adapter.injectAwsAuthAll(baseFragment, ~group="SuperAdmin")
|
|
53
57
|
let parts = decodeFragment(augmented)
|
|
54
|
-
parts.mutations->Array.forEach(
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
parts.mutations->Array.forEach(
|
|
59
|
+
field => {
|
|
60
|
+
expect(field)->toContain(`cognito_groups: ["SuperAdmin"]`)
|
|
61
|
+
},
|
|
62
|
+
)
|
|
57
63
|
})
|
|
58
64
|
|
|
59
65
|
// Regression: `injectAwsAuthAll` used to re-encode the fragment without the
|
|
@@ -68,9 +74,11 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
|
|
|
68
74
|
let parts = decodeFragment(augmented)
|
|
69
75
|
expect(parts.subscriptions->Array.length)->toBe(original.subscriptions->Array.length)
|
|
70
76
|
expect(parts.subscriptions->Array.length)->toBeGreaterThan(0)
|
|
71
|
-
parts.subscriptions->Array.forEach(
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
parts.subscriptions->Array.forEach(
|
|
78
|
+
field => {
|
|
79
|
+
expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
80
|
+
},
|
|
81
|
+
)
|
|
74
82
|
})
|
|
75
83
|
|
|
76
84
|
testSync("admin Plugin aggregate subscription fields survive the round-trip", () => {
|
|
@@ -100,25 +108,20 @@ describe("AppSync_Adapter.injectAwsAuthAll", () => {
|
|
|
100
108
|
describe("AppSync_Adapter.injectAwsAuth", () => {
|
|
101
109
|
testSync("injects auth only on entries with authorization", () => {
|
|
102
110
|
// Build a fragment with known entries
|
|
103
|
-
let mutationEntries: array<
|
|
104
|
-
|
|
111
|
+
let mutationEntries: array<
|
|
112
|
+
ReventlessInfra.Api.mutationSchemaEntry,
|
|
113
|
+
> = ReventlessCore.Platform_AdminApi.mutationEntries(~cloner=false)
|
|
105
114
|
let queryEntries = ReventlessCore.PluginBaseFragment.queryEntries
|
|
106
115
|
|
|
107
116
|
let baseFragment = ReventlessCore.Platform_AdminApi.baseFragment(~cloner=false)
|
|
108
|
-
let augmented = AppSync_Adapter.injectAwsAuth(
|
|
109
|
-
baseFragment,
|
|
110
|
-
~mutationEntries,
|
|
111
|
-
~queryEntries,
|
|
112
|
-
)
|
|
117
|
+
let augmented = AppSync_Adapter.injectAwsAuth(baseFragment, ~mutationEntries, ~queryEntries)
|
|
113
118
|
let parts = decodeFragment(augmented)
|
|
114
119
|
|
|
115
120
|
// Query entries have authorization → should carry the directive
|
|
116
|
-
let queryWithAuth =
|
|
117
|
-
queryEntries->Array.some(entry => entry.authorization->Option.isSome)
|
|
121
|
+
let queryWithAuth = queryEntries->Array.some(entry => entry.authorization->Option.isSome)
|
|
118
122
|
if queryWithAuth {
|
|
119
|
-
let hasAuthQuery =
|
|
120
|
-
field->String.includes("@aws_cognito_user_pools")
|
|
121
|
-
)
|
|
123
|
+
let hasAuthQuery =
|
|
124
|
+
parts.queries->Array.some(field => field->String.includes("@aws_cognito_user_pools"))
|
|
122
125
|
expect(hasAuthQuery)->toBe(true)
|
|
123
126
|
}
|
|
124
127
|
})
|
|
@@ -177,59 +180,37 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
177
180
|
returnTypeName: single,
|
|
178
181
|
stateSchema: S.unknown,
|
|
179
182
|
authorization: None,
|
|
180
|
-
|
|
183
|
+
?permission,
|
|
181
184
|
}
|
|
182
185
|
|
|
183
186
|
testSync("AllowGroups([\"Admin\"]) emits cognito_groups: [\"Admin\"] on mutation", () => {
|
|
184
|
-
let fp = Dict.fromArray([
|
|
185
|
-
"catalog_Category_Archive",
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
let entry = mutationEntry(
|
|
189
|
-
~fieldNames=["catalog_Category_Archive"],
|
|
190
|
-
~fieldPermissions=fp,
|
|
191
|
-
)
|
|
187
|
+
let fp = Dict.fromArray([
|
|
188
|
+
("catalog_Category_Archive", Reventless.Authorization.AllowGroups(["Admin"])),
|
|
189
|
+
])
|
|
190
|
+
let entry = mutationEntry(~fieldNames=["catalog_Category_Archive"], ~fieldPermissions=fp)
|
|
192
191
|
let frag = makeFragment(["catalog_Category_Archive(id: ID!): String"], [])
|
|
193
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
194
|
-
frag,
|
|
195
|
-
~mutationEntries=[entry],
|
|
196
|
-
~queryEntries=[],
|
|
197
|
-
)
|
|
192
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
198
193
|
let parts = decodeFragment(aug)
|
|
199
194
|
let m = parts.mutations->Array.getUnsafe(0)
|
|
200
195
|
expect(m)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
201
196
|
})
|
|
202
197
|
|
|
203
198
|
testSync("AllowGroups multi-group emits comma-separated groups", () => {
|
|
204
|
-
let fp = Dict.fromArray([(
|
|
205
|
-
"p_X",
|
|
206
|
-
Reventless.Authorization.AllowGroups(["Admin", "Editor"]),
|
|
207
|
-
)])
|
|
199
|
+
let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowGroups(["Admin", "Editor"]))])
|
|
208
200
|
let entry = mutationEntry(~fieldNames=["p_X"], ~fieldPermissions=fp)
|
|
209
201
|
let frag = makeFragment(["p_X(id: ID!): String"], [])
|
|
210
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
211
|
-
frag,
|
|
212
|
-
~mutationEntries=[entry],
|
|
213
|
-
~queryEntries=[],
|
|
214
|
-
)
|
|
202
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
215
203
|
let parts = decodeFragment(aug)
|
|
216
|
-
expect(
|
|
217
|
-
|
|
218
|
-
)
|
|
204
|
+
expect(
|
|
205
|
+
parts.mutations->Array.getUnsafe(0),
|
|
206
|
+
)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin", "Editor"])`)
|
|
219
207
|
})
|
|
220
208
|
|
|
221
209
|
testSync("AllowAuthenticated emits the group-less Cognito directive", () => {
|
|
222
|
-
let fp = Dict.fromArray([(
|
|
223
|
-
"p_Add",
|
|
224
|
-
Reventless.Authorization.AllowAuthenticated,
|
|
225
|
-
)])
|
|
210
|
+
let fp = Dict.fromArray([("p_Add", Reventless.Authorization.AllowAuthenticated)])
|
|
226
211
|
let entry = mutationEntry(~fieldNames=["p_Add"], ~fieldPermissions=fp)
|
|
227
212
|
let frag = makeFragment(["p_Add(id: ID!): String"], [])
|
|
228
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
229
|
-
frag,
|
|
230
|
-
~mutationEntries=[entry],
|
|
231
|
-
~queryEntries=[],
|
|
232
|
-
)
|
|
213
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
233
214
|
let parts = decodeFragment(aug)
|
|
234
215
|
// Open, not ungated: the field carries the group-less directive so it stays
|
|
235
216
|
// reachable once defaultAction flips to DENY, but names no group.
|
|
@@ -242,11 +223,7 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
242
223
|
let fp = Dict.fromArray([("p_Hide", Reventless.Authorization.DenyAll)])
|
|
243
224
|
let entry = mutationEntry(~fieldNames=["p_Hide"], ~fieldPermissions=fp)
|
|
244
225
|
let frag = makeFragment(["p_Hide(id: ID!): String"], [])
|
|
245
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
246
|
-
frag,
|
|
247
|
-
~mutationEntries=[entry],
|
|
248
|
-
~queryEntries=[],
|
|
249
|
-
)
|
|
226
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
250
227
|
let parts = decodeFragment(aug)
|
|
251
228
|
expect(parts.mutations->Array.getUnsafe(0))->toContain(`"__deny_all__"`)
|
|
252
229
|
})
|
|
@@ -256,19 +233,9 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
256
233
|
("p_Archive", Reventless.Authorization.AllowGroups(["Admin"])),
|
|
257
234
|
("p_Add", Reventless.Authorization.AllowAuthenticated),
|
|
258
235
|
])
|
|
259
|
-
let entry = mutationEntry(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
)
|
|
263
|
-
let frag = makeFragment(
|
|
264
|
-
["p_Archive(id: ID!): String", "p_Add(name: String!): String"],
|
|
265
|
-
[],
|
|
266
|
-
)
|
|
267
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
268
|
-
frag,
|
|
269
|
-
~mutationEntries=[entry],
|
|
270
|
-
~queryEntries=[],
|
|
271
|
-
)
|
|
236
|
+
let entry = mutationEntry(~fieldNames=["p_Archive", "p_Add"], ~fieldPermissions=fp)
|
|
237
|
+
let frag = makeFragment(["p_Archive(id: ID!): String", "p_Add(name: String!): String"], [])
|
|
238
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
272
239
|
let parts = decodeFragment(aug)
|
|
273
240
|
let archive = parts.mutations->Array.find(f => f->String.includes("p_Archive"))
|
|
274
241
|
let add = parts.mutations->Array.find(f => f->String.includes("p_Add"))
|
|
@@ -295,16 +262,9 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
295
262
|
// paren-first split reliably yields the bare field name.
|
|
296
263
|
let frag = makeFragment(
|
|
297
264
|
[],
|
|
298
|
-
[
|
|
299
|
-
"p_Item(id: ID!): Item",
|
|
300
|
-
"p_Items(first: Int, after: String): ItemConnection!",
|
|
301
|
-
],
|
|
302
|
-
)
|
|
303
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
304
|
-
frag,
|
|
305
|
-
~mutationEntries=[],
|
|
306
|
-
~queryEntries=[entry],
|
|
265
|
+
["p_Item(id: ID!): Item", "p_Items(first: Int, after: String): ItemConnection!"],
|
|
307
266
|
)
|
|
267
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
|
|
308
268
|
let parts = decodeFragment(aug)
|
|
309
269
|
let item = parts.queries->Array.find(f => f->String.includes("p_Item("))
|
|
310
270
|
let items = parts.queries->Array.find(f => f->String.includes("p_Items("))
|
|
@@ -316,13 +276,93 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
316
276
|
}
|
|
317
277
|
})
|
|
318
278
|
|
|
279
|
+
// ── AllowAnonymous is refused, not silently downgraded ────────────────────
|
|
280
|
+
//
|
|
281
|
+
// The defect these cover: `AllowAnonymous` shared `AllowAuthenticated`'s arm
|
|
282
|
+
// and emitted the same group-less directive, which on this Cognito-primary
|
|
283
|
+
// API means *any authenticated caller* — the inverse of the declaration. It
|
|
284
|
+
// deployed green, passed `assertGateable`, and worked on the local platform,
|
|
285
|
+
// whose resolvers call `Authorization.isAllowed` and honour the rule. It
|
|
286
|
+
// failed closed, so no deployment ever reported it.
|
|
287
|
+
|
|
288
|
+
let refuses = (run: unit => 'a): bool =>
|
|
289
|
+
switch run() {
|
|
290
|
+
| _ => false
|
|
291
|
+
| exception _ => true
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let messageOf = (run: unit => 'a): string =>
|
|
295
|
+
switch run() {
|
|
296
|
+
| _ => ""
|
|
297
|
+
| exception JsExn(err) => JsExn.message(err)->Option.getOr("")
|
|
298
|
+
| exception _ => ""
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let anonymousMutation = (~fieldNames) => {
|
|
302
|
+
let fp =
|
|
303
|
+
fieldNames
|
|
304
|
+
->Array.map(n => (n, Reventless.Authorization.AllowAnonymous))
|
|
305
|
+
->Dict.fromArray
|
|
306
|
+
let entry = mutationEntry(~fieldNames, ~fieldPermissions=fp)
|
|
307
|
+
let frag = makeFragment(fieldNames->Array.map(n => `${n}(id: ID!): String`), [])
|
|
308
|
+
() => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
testSync("AllowAnonymous on a mutation fails the deploy", () => {
|
|
312
|
+
expect(refuses(anonymousMutation(~fieldNames=["p_Register"])))->toBe(true)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
// The whole point of the change: two distinct permissions must not produce
|
|
316
|
+
// one outcome. Asserting only "it throws" would still pass if a later edit
|
|
317
|
+
// re-collapsed the arms and dropped the refusal, so pin the contrast.
|
|
318
|
+
testSync("AllowAnonymous and AllowAuthenticated do not behave alike", () => {
|
|
319
|
+
let authenticated = {
|
|
320
|
+
let fp = Dict.fromArray([("p_Register", Reventless.Authorization.AllowAuthenticated)])
|
|
321
|
+
let entry = mutationEntry(~fieldNames=["p_Register"], ~fieldPermissions=fp)
|
|
322
|
+
let frag = makeFragment(["p_Register(id: ID!): String"], [])
|
|
323
|
+
() => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
324
|
+
}
|
|
325
|
+
expect(refuses(authenticated))->toBe(false)
|
|
326
|
+
expect(refuses(anonymousMutation(~fieldNames=["p_Register"])))->toBe(true)
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
testSync("the refusal names the offending field, so it can be found", () => {
|
|
330
|
+
let msg = messageOf(anonymousMutation(~fieldNames=["p_Register"]))
|
|
331
|
+
expect(msg)->toContain("p_Register")
|
|
332
|
+
expect(msg)->toContain("AllowAnonymous")
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
// One deploy should report every offending field. Reporting the first one
|
|
336
|
+
// turns a batch of them into as many failed deploys as there are fields.
|
|
337
|
+
testSync("every offending field is reported, not just the first", () => {
|
|
338
|
+
let msg = messageOf(anonymousMutation(~fieldNames=["p_Register", "p_Confirm"]))
|
|
339
|
+
expect(msg)->toContain("p_Register")
|
|
340
|
+
expect(msg)->toContain("p_Confirm")
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
testSync("AllowAnonymous on a query names BOTH derived field names", () => {
|
|
344
|
+
let entry = queryEntry(
|
|
345
|
+
~single="p_Item",
|
|
346
|
+
~list="p_Items",
|
|
347
|
+
~permission=Some(Reventless.Authorization.AllowAnonymous),
|
|
348
|
+
)
|
|
349
|
+
let frag = makeFragment(
|
|
350
|
+
[],
|
|
351
|
+
["p_Item(id: ID!): Item", "p_Items(first: Int, after: String): ItemConnection!"],
|
|
352
|
+
)
|
|
353
|
+
let run = () => AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
|
|
354
|
+
expect(refuses(run))->toBe(true)
|
|
355
|
+
let msg = messageOf(run)
|
|
356
|
+
// The spec declares one permission and the generator emits two fields from
|
|
357
|
+
// it; naming one would send the author hunting a declaration that is not there.
|
|
358
|
+
expect(msg)->toContain("p_Item")
|
|
359
|
+
expect(msg)->toContain("p_Items")
|
|
360
|
+
})
|
|
361
|
+
|
|
319
362
|
testSync("Spec-level permission wins over legacy authorization field", () => {
|
|
320
363
|
// Legacy {tableName, group} says "Admin"; spec-level says "Manager".
|
|
321
364
|
// Spec-level must win.
|
|
322
|
-
let fp = Dict.fromArray([(
|
|
323
|
-
"p_X",
|
|
324
|
-
Reventless.Authorization.AllowGroups(["Manager"]),
|
|
325
|
-
)])
|
|
365
|
+
let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowGroups(["Manager"]))])
|
|
326
366
|
let entry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
327
367
|
fieldNames: ["p_X"],
|
|
328
368
|
commandSchema: S.unknown,
|
|
@@ -333,44 +373,36 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
333
373
|
fieldPermissions: fp,
|
|
334
374
|
}
|
|
335
375
|
let frag = makeFragment(["p_X(id: ID!): String"], [])
|
|
336
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
337
|
-
frag,
|
|
338
|
-
~mutationEntries=[entry],
|
|
339
|
-
~queryEntries=[],
|
|
340
|
-
)
|
|
376
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
341
377
|
let parts = decodeFragment(aug)
|
|
342
378
|
let m = parts.mutations->Array.getUnsafe(0)
|
|
343
379
|
expect(m)->toContain(`cognito_groups: ["Manager"]`)
|
|
344
380
|
expect(m)->not_->toContain(`"Admin"`)
|
|
345
381
|
})
|
|
346
382
|
|
|
347
|
-
testSync(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
Reventless.Authorization.AllowAuthenticated
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
let m = parts.mutations->Array.getUnsafe(0)
|
|
371
|
-
expect(m)->toContain("@aws_cognito_user_pools")
|
|
372
|
-
expect(m)->not_->toContain("cognito_groups")
|
|
373
|
-
})
|
|
383
|
+
testSync(
|
|
384
|
+
"AllowAuthenticated on a field overrides the legacy authorization (drops the group)",
|
|
385
|
+
() => {
|
|
386
|
+
let fp = Dict.fromArray([("p_X", Reventless.Authorization.AllowAuthenticated)])
|
|
387
|
+
let entry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
388
|
+
fieldNames: ["p_X"],
|
|
389
|
+
commandSchema: S.unknown,
|
|
390
|
+
authorization: {
|
|
391
|
+
Reventless.ReadModel.tableName: "Tbl",
|
|
392
|
+
group: "Admin",
|
|
393
|
+
},
|
|
394
|
+
fieldPermissions: fp,
|
|
395
|
+
}
|
|
396
|
+
let frag = makeFragment(["p_X(id: ID!): String"], [])
|
|
397
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
398
|
+
let parts = decodeFragment(aug)
|
|
399
|
+
// The spec-level AllowAuthenticated wins over the legacy `authorization.group`:
|
|
400
|
+
// the field keeps a directive, but no longer names a group.
|
|
401
|
+
let m = parts.mutations->Array.getUnsafe(0)
|
|
402
|
+
expect(m)->toContain("@aws_cognito_user_pools")
|
|
403
|
+
expect(m)->not_->toContain("cognito_groups")
|
|
404
|
+
},
|
|
405
|
+
)
|
|
374
406
|
})
|
|
375
407
|
|
|
376
408
|
// ── Dual-auth (Cognito + IAM) for deploy-time system callers ────────────────
|
|
@@ -394,7 +426,9 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
|
|
|
394
426
|
let entry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
395
427
|
fieldNames: ["p_Sync"],
|
|
396
428
|
commandSchema: S.unknown,
|
|
397
|
-
fieldPermissions: Dict.fromArray([
|
|
429
|
+
fieldPermissions: Dict.fromArray([
|
|
430
|
+
("p_Sync", Reventless.Authorization.AllowGroups(["Admin"])),
|
|
431
|
+
]),
|
|
398
432
|
systemCallable: true,
|
|
399
433
|
}
|
|
400
434
|
let frag = makeFragment(["p_Sync(id: ID!): String"], [])
|
|
@@ -406,21 +440,24 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
|
|
|
406
440
|
expect(m)->not_->toContain("@aws_auth")
|
|
407
441
|
})
|
|
408
442
|
|
|
409
|
-
testSync(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
443
|
+
testSync(
|
|
444
|
+
"systemCallable mutation without a group restriction stays open to Cognito + IAM",
|
|
445
|
+
() => {
|
|
446
|
+
let entry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
447
|
+
fieldNames: ["p_Sync"],
|
|
448
|
+
commandSchema: S.unknown,
|
|
449
|
+
fieldPermissions: Dict.fromArray([("p_Sync", Reventless.Authorization.AllowAuthenticated)]),
|
|
450
|
+
systemCallable: true,
|
|
451
|
+
}
|
|
452
|
+
let frag = makeFragment(["p_Sync(id: ID!): String"], [])
|
|
453
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[entry], ~queryEntries=[])
|
|
454
|
+
let m = decodeFragment(aug).mutations->Array.getUnsafe(0)
|
|
455
|
+
// Bare @aws_cognito_user_pools (any authenticated Cognito user) + IAM.
|
|
456
|
+
expect(m)->toContain("@aws_cognito_user_pools @aws_iam")
|
|
457
|
+
expect(m)->not_->toContain("cognito_groups")
|
|
458
|
+
expect(m)->not_->toContain("@aws_auth")
|
|
459
|
+
},
|
|
460
|
+
)
|
|
424
461
|
|
|
425
462
|
testSync("a non-systemCallable sibling stays Cognito-only (no @aws_iam)", () => {
|
|
426
463
|
let entry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
@@ -437,11 +474,17 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
|
|
|
437
474
|
let iamEntry: ReventlessInfra.Api.mutationSchemaEntry = {
|
|
438
475
|
fieldNames: ["p_Sync"],
|
|
439
476
|
commandSchema: S.unknown,
|
|
440
|
-
fieldPermissions: Dict.fromArray([
|
|
477
|
+
fieldPermissions: Dict.fromArray([
|
|
478
|
+
("p_Sync", Reventless.Authorization.AllowGroups(["Admin"])),
|
|
479
|
+
]),
|
|
441
480
|
systemCallable: true,
|
|
442
481
|
}
|
|
443
482
|
let frag = makeFragment(["p_Sync(id: ID!): String", "p_Other(id: ID!): String"], [])
|
|
444
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
483
|
+
let aug = AppSync_Adapter.injectAwsAuth(
|
|
484
|
+
frag,
|
|
485
|
+
~mutationEntries=[entry, iamEntry],
|
|
486
|
+
~queryEntries=[],
|
|
487
|
+
)
|
|
445
488
|
let parts = decodeFragment(aug)
|
|
446
489
|
switch parts.mutations->Array.find(f => f->String.includes("p_Other")) {
|
|
447
490
|
| Some(other) =>
|
|
@@ -480,35 +523,39 @@ describe("AppSync_Adapter.injectAwsAuth — systemCallable dual-auth", () => {
|
|
|
480
523
|
}
|
|
481
524
|
})
|
|
482
525
|
|
|
483
|
-
testSync(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
[],
|
|
495
|
-
[
|
|
496
|
-
"p_ItemItems(id: ID!, first: Int): p_ItemConnection!",
|
|
497
|
-
"p_ItemsByIds(ids: [ID!]!): [p_Item]!",
|
|
498
|
-
"p_ItemByOwner(id: ID!, first: Int): p_ItemConnection!",
|
|
499
|
-
"q_Unrelated(id: ID!): String",
|
|
500
|
-
],
|
|
501
|
-
)
|
|
502
|
-
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
|
|
503
|
-
let parts = decodeFragment(aug)
|
|
504
|
-
parts.queries->Array.forEach(field =>
|
|
505
|
-
if field->String.includes("q_Unrelated") {
|
|
506
|
-
expect(field)->not_->toContain("@aws_iam")
|
|
507
|
-
} else {
|
|
508
|
-
expect(field)->toContain("@aws_iam")
|
|
526
|
+
testSync(
|
|
527
|
+
"systemCallable dual-auth extends to derived query fields (Items/ByIds/By<Index>)",
|
|
528
|
+
() => {
|
|
529
|
+
let entry: ReventlessInfra.Api.querySchemaEntry = {
|
|
530
|
+
singleFieldName: "p_Item",
|
|
531
|
+
listFieldName: "p_Items",
|
|
532
|
+
returnTypeName: "p_Item",
|
|
533
|
+
stateSchema: S.unknown,
|
|
534
|
+
authorization: None,
|
|
535
|
+
permission: Reventless.Authorization.AllowGroups(["Admin"]),
|
|
536
|
+
systemCallable: true,
|
|
509
537
|
}
|
|
510
|
-
|
|
511
|
-
|
|
538
|
+
let frag = makeFragment(
|
|
539
|
+
[],
|
|
540
|
+
[
|
|
541
|
+
"p_ItemItems(id: ID!, first: Int): p_ItemConnection!",
|
|
542
|
+
"p_ItemsByIds(ids: [ID!]!): [p_Item]!",
|
|
543
|
+
"p_ItemByOwner(id: ID!, first: Int): p_ItemConnection!",
|
|
544
|
+
"q_Unrelated(id: ID!): String",
|
|
545
|
+
],
|
|
546
|
+
)
|
|
547
|
+
let aug = AppSync_Adapter.injectAwsAuth(frag, ~mutationEntries=[], ~queryEntries=[entry])
|
|
548
|
+
let parts = decodeFragment(aug)
|
|
549
|
+
parts.queries->Array.forEach(
|
|
550
|
+
field =>
|
|
551
|
+
if field->String.includes("q_Unrelated") {
|
|
552
|
+
expect(field)->not_->toContain("@aws_iam")
|
|
553
|
+
} else {
|
|
554
|
+
expect(field)->toContain("@aws_iam")
|
|
555
|
+
},
|
|
556
|
+
)
|
|
557
|
+
},
|
|
558
|
+
)
|
|
512
559
|
})
|
|
513
560
|
|
|
514
561
|
// ── Type-level dual-auth ─────────────────────────────────────────────────────
|
|
@@ -551,15 +598,20 @@ describe("AppSync_Adapter — type-level dual-auth", () => {
|
|
|
551
598
|
|
|
552
599
|
testSync("types prefixed by a callable entry's returnTypeName carry the multi-auth pair", () => {
|
|
553
600
|
let frag = makeFragmentWithTypes(types, ["p_Item(id: ID!): p_Item"])
|
|
554
|
-
let aug = AppSync_Adapter.injectAwsAuth(
|
|
601
|
+
let aug = AppSync_Adapter.injectAwsAuth(
|
|
602
|
+
frag,
|
|
603
|
+
~mutationEntries=[],
|
|
604
|
+
~queryEntries=[callableEntry],
|
|
605
|
+
)
|
|
555
606
|
let parts = decodeFragment(aug)
|
|
556
|
-
parts.types->Array.forEach(
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
607
|
+
parts.types->Array.forEach(
|
|
608
|
+
decl =>
|
|
609
|
+
if decl->String.startsWith("type p_Item") {
|
|
610
|
+
expect(decl)->toContain("@aws_cognito_user_pools @aws_iam {")
|
|
611
|
+
} else {
|
|
612
|
+
// The sibling view's type and the (non-authorizable) input stay untouched.
|
|
613
|
+
expect(decl)->not_->toContain("@aws_iam")
|
|
614
|
+
},
|
|
563
615
|
)
|
|
564
616
|
})
|
|
565
617
|
|
|
@@ -573,25 +625,31 @@ describe("AppSync_Adapter — type-level dual-auth", () => {
|
|
|
573
625
|
decodeFragment(aug).types->Array.forEach(decl => expect(decl)->not_->toContain("@aws_iam"))
|
|
574
626
|
})
|
|
575
627
|
|
|
576
|
-
testSync(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
628
|
+
testSync(
|
|
629
|
+
"stampSharedIamTypes marks PageInfo + CommandResult members on the assembled SDL",
|
|
630
|
+
() => {
|
|
631
|
+
let sdl =
|
|
632
|
+
[
|
|
633
|
+
"interface Node {\n id: ID!\n}",
|
|
634
|
+
"type PageInfo {\n hasNextPage: Boolean!\n}",
|
|
635
|
+
"union CommandResult = CommandAccepted | CommandRejected | CommandPending",
|
|
636
|
+
"type CommandAccepted {\n msgId: ID!\n}",
|
|
637
|
+
"type CommandRejected {\n msgId: ID!\n}",
|
|
638
|
+
"type CommandPending {\n msgId: ID!\n}",
|
|
639
|
+
"type Untouched {\n id: ID!\n}",
|
|
640
|
+
]->Array.join("\n\n")
|
|
641
|
+
let stamped = AppSync_Adapter.stampSharedIamTypes(sdl)
|
|
642
|
+
expect(stamped)->toContain("type PageInfo @aws_cognito_user_pools @aws_iam {")
|
|
643
|
+
expect(stamped)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
|
|
644
|
+
expect(stamped)->toContain("type CommandRejected @aws_cognito_user_pools @aws_iam {")
|
|
645
|
+
expect(stamped)->toContain("type CommandPending @aws_cognito_user_pools @aws_iam {")
|
|
646
|
+
expect(stamped)->toContain("type Untouched {")
|
|
647
|
+
// The union declaration itself takes no directive.
|
|
648
|
+
expect(stamped)->toContain(
|
|
649
|
+
"union CommandResult = CommandAccepted | CommandRejected | CommandPending",
|
|
650
|
+
)
|
|
651
|
+
},
|
|
652
|
+
)
|
|
595
653
|
})
|
|
596
654
|
|
|
597
655
|
describe("AppSync_Adapter.injectAwsAuthAll — ~iamFieldNames", () => {
|
|
@@ -603,20 +661,25 @@ describe("AppSync_Adapter.injectAwsAuthAll — ~iamFieldNames", () => {
|
|
|
603
661
|
decodeFragment(baseFragment).mutations
|
|
604
662
|
->Array.getUnsafe(0)
|
|
605
663
|
->ReventlessCore.GraphQL_Stitcher.extractLeadingName
|
|
606
|
-
let augmented =
|
|
607
|
-
|
|
664
|
+
let augmented = AppSync_Adapter.injectAwsAuthAll(
|
|
665
|
+
baseFragment,
|
|
666
|
+
~group="Admin",
|
|
667
|
+
~iamFieldNames=[firstMutationName],
|
|
668
|
+
)
|
|
608
669
|
let parts = decodeFragment(augmented)
|
|
609
|
-
parts.mutations->Array.forEach(
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
670
|
+
parts.mutations->Array.forEach(
|
|
671
|
+
field => {
|
|
672
|
+
let name = ReventlessCore.GraphQL_Stitcher.extractLeadingName(field)
|
|
673
|
+
if name == firstMutationName {
|
|
674
|
+
expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
675
|
+
expect(field)->toContain("@aws_iam")
|
|
676
|
+
expect(field)->not_->toContain("@aws_auth")
|
|
677
|
+
} else {
|
|
678
|
+
expect(field)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
679
|
+
expect(field)->not_->toContain("@aws_iam")
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
)
|
|
620
683
|
})
|
|
621
684
|
|
|
622
685
|
testSync("default (no ~iamFieldNames) leaves every field Cognito-only", () => {
|
|
@@ -670,10 +733,7 @@ describe("Split mode — empty base fragment", () => {
|
|
|
670
733
|
|
|
671
734
|
testSync("stitching admin base without plugins produces only admin fields", () => {
|
|
672
735
|
let adminBase = ReventlessCore.Platform_AdminApi.baseFragment(~cloner=false)
|
|
673
|
-
let sdl = ReventlessCore.GraphQL_Stitcher.stitch(
|
|
674
|
-
~baseFragment=adminBase,
|
|
675
|
-
~pluginFragments=[],
|
|
676
|
-
)
|
|
736
|
+
let sdl = ReventlessCore.GraphQL_Stitcher.stitch(~baseFragment=adminBase, ~pluginFragments=[])
|
|
677
737
|
expect(sdl)->toContain("Platform_Plugin")
|
|
678
738
|
})
|
|
679
739
|
})
|
|
@@ -688,8 +748,9 @@ describe("Split mode — empty base fragment", () => {
|
|
|
688
748
|
|
|
689
749
|
describe("Merged mode — canonical source documents", () => {
|
|
690
750
|
let assembleCanonicalSourceSdl = (~baseFragment) =>
|
|
691
|
-
AppSync_Adapter.stitchStandaloneWithAwsDirectives(
|
|
692
|
-
|
|
751
|
+
AppSync_Adapter.stitchStandaloneWithAwsDirectives(
|
|
752
|
+
~fragment=baseFragment,
|
|
753
|
+
)->AppSync_SdlDecorate.stampCanonicalTypes
|
|
693
754
|
|
|
694
755
|
// Mirrors Platform.res's domainBaseFragment: no component fields, one
|
|
695
756
|
// Platform_ping so the Query type is non-empty.
|
|
@@ -755,9 +816,7 @@ describe("Merged mode — canonical source documents", () => {
|
|
|
755
816
|
mutations: ["MyPlugin_Item_Create(name: String!): CommandResult"],
|
|
756
817
|
queries: ["MyPlugin_Item(id: ID!): MyPlugin_Item"],
|
|
757
818
|
subscriptions: ["onMyPlugin_Item_Create(id: ID): CommandResult"],
|
|
758
|
-
subscriptionSources: [
|
|
759
|
-
{field: "onMyPlugin_Item_Create", mutations: ["MyPlugin_Item_Create"]},
|
|
760
|
-
],
|
|
819
|
+
subscriptionSources: [{field: "onMyPlugin_Item_Create", mutations: ["MyPlugin_Item_Create"]}],
|
|
761
820
|
})
|
|
762
821
|
|
|
763
822
|
testSync("plugin subgraph document is standalone: relay types included, node omitted", () => {
|
|
@@ -768,13 +827,16 @@ describe("Merged mode — canonical source documents", () => {
|
|
|
768
827
|
expect(sdl)->not_->toContain("node(id: ID!): Node")
|
|
769
828
|
})
|
|
770
829
|
|
|
771
|
-
testSync(
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
830
|
+
testSync(
|
|
831
|
+
"plugin subgraph document carries @aws_subscribe + shared-type IAM stamps, no @canonical",
|
|
832
|
+
() => {
|
|
833
|
+
let sdl = AppSync_Adapter.stitchStandaloneWithAwsDirectives(~fragment=pluginFragment)
|
|
834
|
+
expect(sdl)->toContain(`@aws_subscribe(mutations: ["MyPlugin_Item_Create"])`)
|
|
835
|
+
expect(sdl)->toContain("type CommandAccepted @aws_cognito_user_pools @aws_iam {")
|
|
836
|
+
// Plugin subgraphs stay unstamped — the admin source's canonical defs win.
|
|
837
|
+
expect(sdl)->not_->toContain("@canonical")
|
|
838
|
+
},
|
|
839
|
+
)
|
|
778
840
|
})
|
|
779
841
|
|
|
780
842
|
// ── waitForMergeSuccess — association merge-status poll ─────────────────────
|