Skip to main content

fakecloud_ssm/service/
mod.rs

1mod associations;
2mod automation;
3mod commands;
4mod compliance;
5mod documents;
6mod instances;
7mod inventory;
8mod maintenance;
9mod misc;
10mod ops;
11mod parameters;
12mod patches;
13mod resource_sync;
14mod sessions;
15mod tags;
16
17use std::sync::Arc;
18
19use async_trait::async_trait;
20use http::StatusCode;
21use tokio::sync::Mutex as AsyncMutex;
22
23use fakecloud_core::service::{AwsRequest, AwsResponse, AwsService, AwsServiceError};
24use fakecloud_persistence::SnapshotStore;
25
26use crate::state::{SharedSsmState, SsmSnapshot, SSM_SNAPSHOT_SCHEMA_VERSION};
27
28use fakecloud_secretsmanager::SharedSecretsManagerState;
29
30const PARAMETER_VERSION_LIMIT: i64 = 100;
31
32pub struct SsmService {
33    state: SharedSsmState,
34    secretsmanager_state: Option<SharedSecretsManagerState>,
35    snapshot_store: Option<Arc<dyn SnapshotStore>>,
36    snapshot_lock: Arc<AsyncMutex<()>>,
37    pub(crate) kms_hook: Option<Arc<dyn fakecloud_core::delivery::KmsHook>>,
38}
39
40impl SsmService {
41    pub fn new(state: SharedSsmState) -> Self {
42        Self {
43            state,
44            secretsmanager_state: None,
45            snapshot_store: None,
46            snapshot_lock: Arc::new(AsyncMutex::new(())),
47            kms_hook: None,
48        }
49    }
50
51    pub fn with_secretsmanager(mut self, sm_state: SharedSecretsManagerState) -> Self {
52        self.secretsmanager_state = Some(sm_state);
53        self
54    }
55
56    pub fn with_snapshot_store(mut self, store: Arc<dyn SnapshotStore>) -> Self {
57        self.snapshot_store = Some(store);
58        self
59    }
60
61    pub fn with_kms_hook(mut self, hook: Arc<dyn fakecloud_core::delivery::KmsHook>) -> Self {
62        self.kms_hook = Some(hook);
63        self
64    }
65
66    /// Admin: force a SendCommand result to a specific terminal status
67    /// (e.g. "Failed", "Cancelled", "TimedOut"). Used by tests to
68    /// simulate command failures without waiting on a real SSM agent.
69    /// All invocations on the command move to the same status so
70    /// `GetCommandInvocation` reflects the override on the next read.
71    /// Returns `true` when the command was found and updated.
72    pub fn set_command_status(&self, account_id: &str, command_id: &str, status: &str) -> bool {
73        let mut accounts = self.state.write();
74        let state = accounts.get_or_create(account_id);
75        if let Some(c) = state
76            .commands
77            .iter_mut()
78            .find(|c| c.command_id == command_id)
79        {
80            let now = chrono::Utc::now();
81            let details = commands::friendly_status_details(status);
82            for inv in c.invocations.iter_mut() {
83                inv.status = status.to_string();
84                inv.status_details = details.clone();
85                inv.response_code = match status {
86                    "Success" => 0,
87                    "Pending" | "InProgress" | "Delayed" => -1,
88                    _ => 1,
89                };
90                inv.last_update_at = now;
91            }
92            c.status = status.to_string();
93            return true;
94        }
95        false
96    }
97
98    /// Admin: force a single invocation (or all if `instance_id` is
99    /// `None`) to `Failed` with optional friendlier `status_details`
100    /// and `standard_error_content` overrides. Mirrors what a real SSM
101    /// agent would report when a runShellScript step exits non-zero.
102    /// Returns the number of invocations that were updated.
103    pub fn fail_command_invocation(
104        &self,
105        account_id: &str,
106        command_id: &str,
107        instance_id: Option<&str>,
108        status_details: Option<&str>,
109        standard_error_content: Option<&str>,
110    ) -> usize {
111        let mut accounts = self.state.write();
112        let state = accounts.get_or_create(account_id);
113        let Some(cmd) = state
114            .commands
115            .iter_mut()
116            .find(|c| c.command_id == command_id)
117        else {
118            return 0;
119        };
120        let now = chrono::Utc::now();
121        let mut updated = 0;
122        for inv in cmd.invocations.iter_mut() {
123            if let Some(iid) = instance_id {
124                if inv.instance_id != iid {
125                    continue;
126                }
127            }
128            inv.status = "Failed".to_string();
129            inv.status_details = status_details
130                .map(|s| s.to_string())
131                .unwrap_or_else(|| commands::friendly_status_details("Failed"));
132            if let Some(err) = standard_error_content {
133                inv.standard_error_content = err.to_string();
134            }
135            inv.response_code = 1;
136            inv.last_update_at = now;
137            updated += 1;
138        }
139        if updated > 0 {
140            cmd.status = commands::aggregate_command_status(&cmd.invocations);
141        }
142        updated
143    }
144
145    /// Admin: read out the parameter-policy event log for the given
146    /// account. Used by tests to verify that Expiration deletions and
147    /// notification windows actually fired without standing up an
148    /// EventBridge target. Reads also tick the lazy policy evaluator so
149    /// callers don't have to issue a Get* call first.
150    pub fn parameter_policy_events(
151        &self,
152        account_id: &str,
153    ) -> Vec<crate::state::ParameterPolicyEvent> {
154        let mut accounts = self.state.write();
155        let state = accounts.get_or_create(account_id);
156        parameters::purge_expired_params(state);
157        parameters::tick_policy_notifications(state);
158        state.parameter_policy_events.clone()
159    }
160
161    /// Admin: drop the recorded parameter-policy event log for the
162    /// given account. Tests use this to reset between assertions.
163    pub fn clear_parameter_policy_events(&self, account_id: &str) {
164        let mut accounts = self.state.write();
165        let state = accounts.get_or_create(account_id);
166        state.parameter_policy_events.clear();
167    }
168
169    /// Admin: inject a fake SSM session record so DescribeSessions /
170    /// TerminateSession round-trip without going through StartSession (which
171    /// returns the Smithy-declared `TargetNotConnected` unless
172    /// `FAKECLOUD_SSM_SESSION_ECHO=1`). The injected
173    /// session is otherwise indistinguishable from one created by StartSession
174    /// in echo mode. Returns the assigned `SessionId`.
175    #[allow(clippy::too_many_arguments)]
176    pub fn inject_session(
177        &self,
178        account_id: &str,
179        target: &str,
180        status: Option<&str>,
181        owner: Option<&str>,
182        reason: Option<&str>,
183        session_id: Option<&str>,
184    ) -> String {
185        let now = chrono::Utc::now();
186        let mut accounts = self.state.write();
187        let state = accounts.get_or_create(account_id);
188        let id = match session_id {
189            Some(s) if !s.is_empty() => s.to_string(),
190            _ => {
191                state.session_counter += 1;
192                format!("session-{:012x}", state.session_counter)
193            }
194        };
195        let resolved_status = status.unwrap_or("Connected").to_string();
196        let end_date = if resolved_status == "Terminated" {
197            Some(now)
198        } else {
199            None
200        };
201        let resolved_owner = owner.map(|s| s.to_string()).unwrap_or_else(|| {
202            fakecloud_aws::arn::Arn::global("iam", &state.account_id, "root").to_string()
203        });
204        let session = crate::state::SsmSession {
205            session_id: id.clone(),
206            target: target.to_string(),
207            status: resolved_status,
208            start_date: now,
209            end_date,
210            owner: resolved_owner,
211            reason: reason.map(|s| s.to_string()),
212        };
213        state.sessions.insert(id.clone(), session);
214        id
215    }
216
217    /// Persist current state as a snapshot. Held across the
218    /// clone-serialize-write sequence to prevent stale-last writes,
219    /// with serde + file I/O offloaded to the blocking pool.
220    async fn save_snapshot(&self) {
221        save_ssm_snapshot(
222            &self.state,
223            self.snapshot_store.clone(),
224            &self.snapshot_lock,
225        )
226        .await;
227    }
228
229    /// Build a hook that persists the current SSM state when invoked, or `None`
230    /// in memory mode (no snapshot store). The CloudFormation provisioner
231    /// mutates `state` directly and uses this to write a CFN-provisioned
232    /// resource through to disk, the same way a direct mutating API call would.
233    pub fn snapshot_hook(&self) -> Option<fakecloud_persistence::SnapshotHook> {
234        let store = self.snapshot_store.clone()?;
235        let state = self.state.clone();
236        let lock = self.snapshot_lock.clone();
237        Some(Arc::new(move || {
238            let state = state.clone();
239            let store = store.clone();
240            let lock = lock.clone();
241            Box::pin(async move {
242                save_ssm_snapshot(&state, Some(store), &lock).await;
243            })
244        }))
245    }
246}
247
248/// Persist the current SSM state as a snapshot. Offloads the serde + blocking
249/// file write to the Tokio blocking pool. Noop when `store` is `None` (memory
250/// mode). Shared by `SsmService::save_snapshot` and the CloudFormation
251/// provisioner's post-provision persist hook so both route through the same
252/// serialize-and-write path.
253pub async fn save_ssm_snapshot(
254    state: &SharedSsmState,
255    store: Option<Arc<dyn SnapshotStore>>,
256    lock: &AsyncMutex<()>,
257) {
258    let Some(store) = store else {
259        return;
260    };
261    let _guard = lock.lock().await;
262    let snapshot = SsmSnapshot {
263        schema_version: SSM_SNAPSHOT_SCHEMA_VERSION,
264        state: None,
265        accounts: Some(state.read().clone()),
266    };
267    let join = tokio::task::spawn_blocking(move || -> std::io::Result<()> {
268        let bytes = serde_json::to_vec(&snapshot)
269            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?;
270        store.save(&bytes)
271    })
272    .await;
273    match join {
274        Ok(Ok(())) => {}
275        Ok(Err(err)) => tracing::error!(%err, "failed to write ssm snapshot"),
276        Err(err) => tracing::error!(%err, "ssm snapshot task panicked"),
277    }
278}
279
280#[async_trait]
281impl AwsService for SsmService {
282    fn service_name(&self) -> &str {
283        "ssm"
284    }
285
286    async fn handle(&self, req: AwsRequest) -> Result<AwsResponse, AwsServiceError> {
287        let mutates = !is_read_only_action(req.action.as_str());
288        let result = match req.action.as_str() {
289            "PutParameter" => self.put_parameter(&req),
290            "GetParameter" => self.get_parameter(&req),
291            "GetParameters" => self.get_parameters(&req),
292            "GetParametersByPath" => self.get_parameters_by_path(&req),
293            "DeleteParameter" => self.delete_parameter(&req),
294            "DeleteParameters" => self.delete_parameters(&req),
295            "DescribeParameters" => self.describe_parameters(&req),
296            "GetParameterHistory" => self.get_parameter_history(&req),
297            "AddTagsToResource" => self.add_tags_to_resource(&req),
298            "RemoveTagsFromResource" => self.remove_tags_from_resource(&req),
299            "ListTagsForResource" => self.list_tags_for_resource(&req),
300            "LabelParameterVersion" => self.label_parameter_version(&req),
301            "UnlabelParameterVersion" => self.unlabel_parameter_version(&req),
302            "CreateDocument" => self.create_document(&req),
303            "GetDocument" => self.get_document(&req),
304            "DeleteDocument" => self.delete_document(&req),
305            "UpdateDocument" => self.update_document(&req),
306            "DescribeDocument" => self.describe_document(&req),
307            "UpdateDocumentDefaultVersion" => self.update_document_default_version(&req),
308            "ListDocuments" => self.list_documents(&req),
309            "DescribeDocumentPermission" => self.describe_document_permission(&req),
310            "ModifyDocumentPermission" => self.modify_document_permission(&req),
311            "SendCommand" => self.send_command(&req),
312            "ListCommands" => self.list_commands(&req),
313            "GetCommandInvocation" => self.get_command_invocation(&req),
314            "ListCommandInvocations" => self.list_command_invocations(&req),
315            "CancelCommand" => self.cancel_command(&req),
316            "CreateMaintenanceWindow" => self.create_maintenance_window(&req),
317            "DescribeMaintenanceWindows" => self.describe_maintenance_windows(&req),
318            "GetMaintenanceWindow" => self.get_maintenance_window(&req),
319            "DeleteMaintenanceWindow" => self.delete_maintenance_window(&req),
320            "UpdateMaintenanceWindow" => self.update_maintenance_window(&req),
321            "RegisterTargetWithMaintenanceWindow" => {
322                self.register_target_with_maintenance_window(&req)
323            }
324            "DeregisterTargetFromMaintenanceWindow" => {
325                self.deregister_target_from_maintenance_window(&req)
326            }
327            "DescribeMaintenanceWindowTargets" => self.describe_maintenance_window_targets(&req),
328            "RegisterTaskWithMaintenanceWindow" => self.register_task_with_maintenance_window(&req),
329            "DeregisterTaskFromMaintenanceWindow" => {
330                self.deregister_task_from_maintenance_window(&req)
331            }
332            "DescribeMaintenanceWindowTasks" => self.describe_maintenance_window_tasks(&req),
333            "CreatePatchBaseline" => self.create_patch_baseline(&req),
334            "DeletePatchBaseline" => self.delete_patch_baseline(&req),
335            "DescribePatchBaselines" => self.describe_patch_baselines(&req),
336            "GetPatchBaseline" => self.get_patch_baseline(&req),
337            "RegisterPatchBaselineForPatchGroup" => {
338                self.register_patch_baseline_for_patch_group(&req)
339            }
340            "DeregisterPatchBaselineForPatchGroup" => {
341                self.deregister_patch_baseline_for_patch_group(&req)
342            }
343            "GetPatchBaselineForPatchGroup" => self.get_patch_baseline_for_patch_group(&req),
344            "DescribePatchGroups" => self.describe_patch_groups(&req),
345            // Associations
346            "CreateAssociation" => self.create_association(&req),
347            "DescribeAssociation" => self.describe_association(&req),
348            "DeleteAssociation" => self.delete_association(&req),
349            "ListAssociations" => self.list_associations(&req),
350            "UpdateAssociation" => self.update_association(&req),
351            "ListAssociationVersions" => self.list_association_versions(&req),
352            "UpdateAssociationStatus" => self.update_association_status(&req),
353            "StartAssociationsOnce" => self.start_associations_once(&req),
354            "CreateAssociationBatch" => self.create_association_batch(&req),
355            "DescribeAssociationExecutions" => self.describe_association_executions(&req),
356            "DescribeAssociationExecutionTargets" => {
357                self.describe_association_execution_targets(&req)
358            }
359            // OpsItems
360            "CreateOpsItem" => self.create_ops_item(&req),
361            "GetOpsItem" => self.get_ops_item(&req),
362            "UpdateOpsItem" => self.update_ops_item(&req),
363            "DeleteOpsItem" => self.delete_ops_item(&req),
364            "DescribeOpsItems" => self.describe_ops_items(&req),
365            // Document extras
366            "ListDocumentVersions" => self.list_document_versions(&req),
367            "ListDocumentMetadataHistory" => self.list_document_metadata_history(&req),
368            "UpdateDocumentMetadata" => self.update_document_metadata(&req),
369            // Resource policies
370            "PutResourcePolicy" => self.put_resource_policy(&req),
371            "GetResourcePolicies" => self.get_resource_policies(&req),
372            "DeleteResourcePolicy" => self.delete_resource_policy(&req),
373            // Inventory
374            "PutInventory" => self.put_inventory(&req),
375            "GetInventory" => self.get_inventory(&req),
376            "GetInventorySchema" => self.get_inventory_schema(&req),
377            "ListInventoryEntries" => self.list_inventory_entries(&req),
378            "DeleteInventory" => self.delete_inventory(&req),
379            "DescribeInventoryDeletions" => self.describe_inventory_deletions(&req),
380            // Compliance
381            "PutComplianceItems" => self.put_compliance_items(&req),
382            "ListComplianceItems" => self.list_compliance_items(&req),
383            "ListComplianceSummaries" => self.list_compliance_summaries(&req),
384            "ListResourceComplianceSummaries" => self.list_resource_compliance_summaries(&req),
385            // Maintenance window details
386            "UpdateMaintenanceWindowTarget" => self.update_maintenance_window_target(&req),
387            "UpdateMaintenanceWindowTask" => self.update_maintenance_window_task(&req),
388            "GetMaintenanceWindowTask" => self.get_maintenance_window_task(&req),
389            "GetMaintenanceWindowExecution" => self.get_maintenance_window_execution(&req),
390            "GetMaintenanceWindowExecutionTask" => self.get_maintenance_window_execution_task(&req),
391            "GetMaintenanceWindowExecutionTaskInvocation" => {
392                self.get_maintenance_window_execution_task_invocation(&req)
393            }
394            "DescribeMaintenanceWindowExecutions" => {
395                self.describe_maintenance_window_executions(&req)
396            }
397            "DescribeMaintenanceWindowExecutionTasks" => {
398                self.describe_maintenance_window_execution_tasks(&req)
399            }
400            "DescribeMaintenanceWindowExecutionTaskInvocations" => {
401                self.describe_maintenance_window_execution_task_invocations(&req)
402            }
403            "DescribeMaintenanceWindowSchedule" => self.describe_maintenance_window_schedule(&req),
404            "DescribeMaintenanceWindowsForTarget" => {
405                self.describe_maintenance_windows_for_target(&req)
406            }
407            "CancelMaintenanceWindowExecution" => self.cancel_maintenance_window_execution(&req),
408            // Patch management details
409            "UpdatePatchBaseline" => self.update_patch_baseline(&req),
410            "DescribeInstancePatchStates" => self.describe_instance_patch_states(&req),
411            "DescribeInstancePatchStatesForPatchGroup" => {
412                self.describe_instance_patch_states_for_patch_group(&req)
413            }
414            "DescribeInstancePatches" => self.describe_instance_patches(&req),
415            "DescribeEffectivePatchesForPatchBaseline" => {
416                self.describe_effective_patches_for_patch_baseline(&req)
417            }
418            "GetDeployablePatchSnapshotForInstance" => {
419                self.get_deployable_patch_snapshot_for_instance(&req)
420            }
421            // Resource data sync
422            "CreateResourceDataSync" => self.create_resource_data_sync(&req),
423            "DeleteResourceDataSync" => self.delete_resource_data_sync(&req),
424            "ListResourceDataSync" => self.list_resource_data_sync(&req),
425            "UpdateResourceDataSync" => self.update_resource_data_sync(&req),
426            // OpsItem related items
427            "AssociateOpsItemRelatedItem" => self.associate_ops_item_related_item(&req),
428            "DisassociateOpsItemRelatedItem" => self.disassociate_ops_item_related_item(&req),
429            "ListOpsItemRelatedItems" => self.list_ops_item_related_items(&req),
430            "ListOpsItemEvents" => self.list_ops_item_events(&req),
431            // OpsMetadata
432            "CreateOpsMetadata" => self.create_ops_metadata(&req),
433            "GetOpsMetadata" => self.get_ops_metadata(&req),
434            "UpdateOpsMetadata" => self.update_ops_metadata(&req),
435            "DeleteOpsMetadata" => self.delete_ops_metadata(&req),
436            "ListOpsMetadata" => self.list_ops_metadata(&req),
437            // OpsMetadata extras
438            "GetOpsSummary" => self.get_ops_summary(&req),
439            // Automation
440            "StartAutomationExecution" => self.start_automation_execution(&req),
441            "StopAutomationExecution" => self.stop_automation_execution(&req),
442            "GetAutomationExecution" => self.get_automation_execution(&req),
443            "DescribeAutomationExecutions" => self.describe_automation_executions(&req),
444            "DescribeAutomationStepExecutions" => self.describe_automation_step_executions(&req),
445            "SendAutomationSignal" => self.send_automation_signal(&req),
446            "StartChangeRequestExecution" => self.start_change_request_execution(&req),
447            "StartExecutionPreview" => self.start_execution_preview(&req),
448            "GetExecutionPreview" => self.get_execution_preview(&req),
449            // Sessions
450            "StartSession" => self.start_session(&req),
451            "ResumeSession" => self.resume_session(&req),
452            "TerminateSession" => self.terminate_session(&req),
453            "DescribeSessions" => self.describe_sessions(&req),
454            "StartAccessRequest" => self.start_access_request(&req),
455            "GetAccessToken" => self.get_access_token(&req),
456            // Managed instances
457            "CreateActivation" => self.create_activation(&req),
458            "DeleteActivation" => self.delete_activation(&req),
459            "DescribeActivations" => self.describe_activations(&req),
460            "DeregisterManagedInstance" => self.deregister_managed_instance(&req),
461            "DescribeInstanceInformation" => self.describe_instance_information(&req),
462            "DescribeInstanceProperties" => self.describe_instance_properties(&req),
463            "UpdateManagedInstanceRole" => self.update_managed_instance_role(&req),
464            // Other
465            "ListNodes" => self.list_nodes(&req),
466            "ListNodesSummary" => self.list_nodes_summary(&req),
467            "DescribeEffectiveInstanceAssociations" => {
468                self.describe_effective_instance_associations(&req)
469            }
470            "DescribeInstanceAssociationsStatus" => {
471                self.describe_instance_associations_status(&req)
472            }
473            // Synthetic defaults (no managed-instance fleet to track) and
474            // service settings backed by real per-account state.
475            "GetConnectionStatus" => self.get_connection_status(&req),
476            "GetCalendarState" => self.get_calendar_state(&req),
477            "DescribePatchGroupState" => self.describe_patch_group_state(&req),
478            "DescribePatchProperties" => self.describe_patch_properties(&req),
479            "GetDefaultPatchBaseline" => self.get_default_patch_baseline(&req),
480            "RegisterDefaultPatchBaseline" => self.register_default_patch_baseline(&req),
481            "DescribeAvailablePatches" => self.describe_available_patches(&req),
482            "GetServiceSetting" => self.get_service_setting(&req),
483            "ResetServiceSetting" => self.reset_service_setting(&req),
484            "UpdateServiceSetting" => self.update_service_setting(&req),
485            _ => Err(AwsServiceError::action_not_implemented("ssm", &req.action)),
486        };
487        if mutates && matches!(result.as_ref(), Ok(resp) if resp.status.is_success()) {
488            self.save_snapshot().await;
489        }
490        result
491    }
492
493    fn supported_actions(&self) -> &[&str] {
494        &[
495            "PutParameter",
496            "GetParameter",
497            "GetParameters",
498            "GetParametersByPath",
499            "DeleteParameter",
500            "DeleteParameters",
501            "DescribeParameters",
502            "GetParameterHistory",
503            "AddTagsToResource",
504            "RemoveTagsFromResource",
505            "ListTagsForResource",
506            "LabelParameterVersion",
507            "UnlabelParameterVersion",
508            "CreateDocument",
509            "GetDocument",
510            "DeleteDocument",
511            "UpdateDocument",
512            "DescribeDocument",
513            "UpdateDocumentDefaultVersion",
514            "ListDocuments",
515            "DescribeDocumentPermission",
516            "ModifyDocumentPermission",
517            "SendCommand",
518            "ListCommands",
519            "GetCommandInvocation",
520            "ListCommandInvocations",
521            "CancelCommand",
522            "CreateMaintenanceWindow",
523            "DescribeMaintenanceWindows",
524            "GetMaintenanceWindow",
525            "DeleteMaintenanceWindow",
526            "UpdateMaintenanceWindow",
527            "RegisterTargetWithMaintenanceWindow",
528            "DeregisterTargetFromMaintenanceWindow",
529            "DescribeMaintenanceWindowTargets",
530            "RegisterTaskWithMaintenanceWindow",
531            "DeregisterTaskFromMaintenanceWindow",
532            "DescribeMaintenanceWindowTasks",
533            "CreatePatchBaseline",
534            "DeletePatchBaseline",
535            "DescribePatchBaselines",
536            "GetPatchBaseline",
537            "RegisterPatchBaselineForPatchGroup",
538            "DeregisterPatchBaselineForPatchGroup",
539            "GetPatchBaselineForPatchGroup",
540            "DescribePatchGroups",
541            // Associations
542            "CreateAssociation",
543            "DescribeAssociation",
544            "DeleteAssociation",
545            "ListAssociations",
546            "UpdateAssociation",
547            "ListAssociationVersions",
548            "UpdateAssociationStatus",
549            "StartAssociationsOnce",
550            "CreateAssociationBatch",
551            "DescribeAssociationExecutions",
552            "DescribeAssociationExecutionTargets",
553            // OpsItems
554            "CreateOpsItem",
555            "GetOpsItem",
556            "UpdateOpsItem",
557            "DeleteOpsItem",
558            "DescribeOpsItems",
559            // Document extras
560            "ListDocumentVersions",
561            "ListDocumentMetadataHistory",
562            "UpdateDocumentMetadata",
563            // Resource policies
564            "PutResourcePolicy",
565            "GetResourcePolicies",
566            "DeleteResourcePolicy",
567            // Inventory
568            "PutInventory",
569            "GetInventory",
570            "GetInventorySchema",
571            "ListInventoryEntries",
572            "DeleteInventory",
573            "DescribeInventoryDeletions",
574            // Compliance
575            "PutComplianceItems",
576            "ListComplianceItems",
577            "ListComplianceSummaries",
578            "ListResourceComplianceSummaries",
579            // Maintenance window details
580            "UpdateMaintenanceWindowTarget",
581            "UpdateMaintenanceWindowTask",
582            "GetMaintenanceWindowTask",
583            "GetMaintenanceWindowExecution",
584            "GetMaintenanceWindowExecutionTask",
585            "GetMaintenanceWindowExecutionTaskInvocation",
586            "DescribeMaintenanceWindowExecutions",
587            "DescribeMaintenanceWindowExecutionTasks",
588            "DescribeMaintenanceWindowExecutionTaskInvocations",
589            "DescribeMaintenanceWindowSchedule",
590            "DescribeMaintenanceWindowsForTarget",
591            "CancelMaintenanceWindowExecution",
592            // Patch management details
593            "UpdatePatchBaseline",
594            "DescribeInstancePatchStates",
595            "DescribeInstancePatchStatesForPatchGroup",
596            "DescribeInstancePatches",
597            "DescribeEffectivePatchesForPatchBaseline",
598            "GetDeployablePatchSnapshotForInstance",
599            // Resource data sync
600            "CreateResourceDataSync",
601            "DeleteResourceDataSync",
602            "ListResourceDataSync",
603            "UpdateResourceDataSync",
604            // OpsItem related items
605            "AssociateOpsItemRelatedItem",
606            "DisassociateOpsItemRelatedItem",
607            "ListOpsItemRelatedItems",
608            "ListOpsItemEvents",
609            // OpsMetadata
610            "CreateOpsMetadata",
611            "GetOpsMetadata",
612            "UpdateOpsMetadata",
613            "DeleteOpsMetadata",
614            "ListOpsMetadata",
615            // OpsMetadata extras
616            "GetOpsSummary",
617            // Automation
618            "StartAutomationExecution",
619            "StopAutomationExecution",
620            "GetAutomationExecution",
621            "DescribeAutomationExecutions",
622            "DescribeAutomationStepExecutions",
623            "SendAutomationSignal",
624            "StartChangeRequestExecution",
625            "StartExecutionPreview",
626            "GetExecutionPreview",
627            // Sessions
628            "StartSession",
629            "ResumeSession",
630            "TerminateSession",
631            "DescribeSessions",
632            "StartAccessRequest",
633            "GetAccessToken",
634            // Managed instances
635            "CreateActivation",
636            "DeleteActivation",
637            "DescribeActivations",
638            "DeregisterManagedInstance",
639            "DescribeInstanceInformation",
640            "DescribeInstanceProperties",
641            "UpdateManagedInstanceRole",
642            // Other
643            "ListNodes",
644            "ListNodesSummary",
645            "DescribeEffectiveInstanceAssociations",
646            "DescribeInstanceAssociationsStatus",
647            // Synthetic defaults + service settings
648            "GetConnectionStatus",
649            "GetCalendarState",
650            "DescribePatchGroupState",
651            "DescribePatchProperties",
652            "GetDefaultPatchBaseline",
653            "RegisterDefaultPatchBaseline",
654            "DescribeAvailablePatches",
655            "GetServiceSetting",
656            "ResetServiceSetting",
657            "UpdateServiceSetting",
658        ]
659    }
660}
661
662mod helpers;
663pub(crate) use helpers::*;
664
665#[cfg(test)]
666mod tests;