diff --git a/reconcile/cli.py b/reconcile/cli.py index 84ec4037ff..dd62ccd309 100644 --- a/reconcile/cli.py +++ b/reconcile/cli.py @@ -1962,6 +1962,14 @@ def quay_membership(ctx: click.Context) -> None: run_integration(reconcile.quay_membership, ctx) +@integration.command(short_help="Manages robot accounts in Quay organizations.") +@click.pass_context +def quay_robot_accounts(ctx: click.Context) -> None: + import reconcile.quay_robot_accounts + + run_integration(reconcile.quay_robot_accounts, ctx) + + @integration.command(short_help="Mirrors external images into GCP Artifact Registry.") @click.pass_context @binary(["skopeo"]) diff --git a/reconcile/gql_definitions/introspection.json b/reconcile/gql_definitions/introspection.json index 0942f90334..7c8d6da28b 100644 --- a/reconcile/gql_definitions/introspection.json +++ b/reconcile/gql_definitions/introspection.json @@ -350,6 +350,47 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "quay_robots_v1", + "description": null, + "args": [ + { + "name": "path", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "filter", + "description": null, + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "QuayRobot_v1", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "roles_v1", "description": null, @@ -4487,6 +4528,16 @@ "name": "ExternalUser_v1", "ofType": null }, + { + "kind": "OBJECT", + "name": "QuayOrg_v1", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "QuayInstance_v1", + "ofType": null + }, { "kind": "OBJECT", "name": "CredentialsRequest_v1", @@ -4557,31 +4608,11 @@ "name": "AppQuayRepos_v1", "ofType": null }, - { - "kind": "OBJECT", - "name": "QuayOrg_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "QuayInstance_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "PermissionQuayOrgTeam_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "AppEscalationPolicy_v1", "ofType": null }, - { - "kind": "OBJECT", - "name": "PermissionSlackUsergroup_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "SlackWorkspace_v1", @@ -4697,11 +4728,6 @@ "name": "AutomatedActionsInstance_v1", "ofType": null }, - { - "kind": "OBJECT", - "name": "PermissionAutomatedActions_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "AWSVPC_v1", @@ -4732,11 +4758,6 @@ "name": "VaultAuth_v1", "ofType": null }, - { - "kind": "OBJECT", - "name": "PermissionGithubOrgTeam_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "VaultPolicy_v1", @@ -4792,11 +4813,6 @@ "name": "UnleashProject_v1", "ofType": null }, - { - "kind": "OBJECT", - "name": "FeatureToggleUnleash_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "ResourceTemplateTest_v1", @@ -4882,95 +4898,10 @@ "name": "SaasResourceTemplateTargetReference_v2", "ofType": null }, - { - "kind": "OBJECT", - "name": "PipelinesProviderTekton_v1", - "ofType": null - }, { "kind": "OBJECT", "name": "PipelinesProviderTektonProviderDefaults_v1", "ofType": null - }, - { - "kind": "OBJECT", - "name": "OidcPermissionVault_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "OidcPermissionAcs_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "PermissionGithubOrg_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "PermissionJenkinsRole_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "PermissionGitlabGroupMembership_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "EndpointMonitoringProviderBlackboxExporter_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "EndpointMonitoringProviderSignalFx_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionActionList_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionCreateToken_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionExternalResourceFlushElastiCache_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionExternalResourceRdsReboot_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionExternalResourceRdsSnapshot_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionNoOp_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionOpenshiftTriggerCronjob_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionOpenshiftWorkloadDelete_v1", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "AutomatedActionOpenshiftWorkloadRestart_v1", - "ofType": null } ] }, @@ -11856,6 +11787,30 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "quay_robots", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "QuayRobot_v1", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -14374,7 +14329,7 @@ }, { "kind": "OBJECT", - "name": "CredentialsRequest_v1", + "name": "QuayRobot_v1", "description": null, "fields": [ { @@ -14442,44 +14397,72 @@ "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "user", + "name": "quay_username", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "quay_org", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "QuayOrg_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "repositories", + "description": null, + "args": [], + "type": { + "kind": "LIST", "name": null, "ofType": { - "kind": "OBJECT", - "name": "User_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "QuayRepository_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "credentials", + "name": "teams", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } } }, "isDeprecated": false, @@ -14487,19 +14470,13 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "AppInterfaceSqlQuery_v1", + "name": "QuayOrg_v1", "description": null, "fields": [ { @@ -14563,15 +14540,15 @@ "deprecationReason": null }, { - "name": "namespace", + "name": "description", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "Namespace_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -14579,55 +14556,63 @@ "deprecationReason": null }, { - "name": "identifier", + "name": "mirror", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "OBJECT", + "name": "QuayOrg_v1", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "requestor", + "name": "mirrorFilters", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "User_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "QuayOrgMirrorFilter_v1", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "overrides", + "name": "managedRepos", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "SqlEmailOverrides_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "output", + "name": "instance", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "QuayInstance_v1", "ofType": null } }, @@ -14635,7 +14620,7 @@ "deprecationReason": null }, { - "name": "schedule", + "name": "serverUrl", "description": null, "args": [], "type": { @@ -14647,45 +14632,49 @@ "deprecationReason": null }, { - "name": "delete", + "name": "managedTeams", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "query", + "name": "automationToken", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "VaultSecret_v1", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "queries", + "name": "pushCredentials", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } + "kind": "OBJECT", + "name": "VaultSecret_v1", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -14704,65 +14693,61 @@ }, { "kind": "OBJECT", - "name": "SqlEmailOverrides_v1", + "name": "QuayOrgMirrorFilter_v1", "description": null, "fields": [ { - "name": "db_host", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "db_port", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "db_name", + "name": "name", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "db_user", + "name": "tags", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "db_password", + "name": "tagsExclude", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null @@ -14775,7 +14760,7 @@ }, { "kind": "OBJECT", - "name": "GabiInstance_v1", + "name": "QuayInstance_v1", "description": null, "fields": [ { @@ -14855,91 +14840,7 @@ "deprecationReason": null }, { - "name": "readReplicasWaiverPledge", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "signoffManagers", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "User_v1", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "users", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "User_v1", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instances", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "GabiNamespace_v1", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "expirationDate", + "name": "url", "description": null, "args": [], "type": { @@ -14968,11 +14869,11 @@ }, { "kind": "OBJECT", - "name": "GabiNamespace_v1", + "name": "QuayRepository_v1", "description": null, "fields": [ { - "name": "account", + "name": "name", "description": null, "args": [], "type": { @@ -14988,7 +14889,7 @@ "deprecationReason": null }, { - "name": "identifier", + "name": "permission", "description": null, "args": [], "type": { @@ -15002,22 +14903,6 @@ }, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "namespace", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Namespace_v1", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null } ], "inputFields": null, @@ -15027,7 +14912,7 @@ }, { "kind": "OBJECT", - "name": "Schedule_v1", + "name": "CredentialsRequest_v1", "description": null, "fields": [ { @@ -15062,6 +14947,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "labels", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "name", "description": null, @@ -15083,32 +14980,44 @@ "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "schedule", + "name": "user", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "ScheduleEntry_v1", - "ofType": null - } - } + "kind": "OBJECT", + "name": "User_v1", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "credentials", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, @@ -15128,11 +15037,11 @@ }, { "kind": "OBJECT", - "name": "ScheduleEntry_v1", + "name": "AppInterfaceSqlQuery_v1", "description": null, "fields": [ { - "name": "start", + "name": "schema", "description": null, "args": [], "type": { @@ -15148,7 +15057,7 @@ "deprecationReason": null }, { - "name": "end", + "name": "path", "description": null, "args": [], "type": { @@ -15164,42 +15073,19 @@ "deprecationReason": null }, { - "name": "users", + "name": "labels", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "User_v1", - "ofType": null - } - } - } + "kind": "SCALAR", + "name": "JSON", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INTERFACE", - "name": "AWSAccountSharingOption_v1", - "description": null, - "fields": [ + }, { - "name": "provider", + "name": "name", "description": null, "args": [], "type": { @@ -15215,7 +15101,7 @@ "deprecationReason": null }, { - "name": "account", + "name": "namespace", "description": null, "args": [], "type": { @@ -15223,32 +15109,15 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "AWSAccount_v1", + "name": "Namespace_v1", "ofType": null } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "AWSAccountSharingOptionAMI_v1", - "ofType": null - } - ] - }, - { - "kind": "INTERFACE", - "name": "AWSAccountCleanupOption_v1", - "description": null, - "fields": [ + }, { - "name": "provider", + "name": "identifier", "description": null, "args": [], "type": { @@ -15262,47 +15131,33 @@ }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "AWSAccountCleanupOptionAMI_v1", - "ofType": null }, { - "kind": "OBJECT", - "name": "AWSAccountCleanupOptionCloudWatch_v1", - "ofType": null - } - ] - }, - { - "kind": "OBJECT", - "name": "TerraformStateAWS_v1", - "description": null, - "fields": [ + "name": "requestor", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "User_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { - "name": "schema", + "name": "overrides", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "OBJECT", + "name": "SqlEmailOverrides_v1", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "path", + "name": "output", "description": null, "args": [], "type": { @@ -15318,71 +15173,55 @@ "deprecationReason": null }, { - "name": "provider", + "name": "schedule", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "bucket", + "name": "delete", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "region", + "name": "query", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "integrations", + "name": "queries", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AWSTerraformStateIntegrations_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } } }, @@ -15392,11 +15231,6 @@ ], "inputFields": null, "interfaces": [ - { - "kind": "INTERFACE", - "name": "TerraformState_v1", - "ofType": null - }, { "kind": "INTERFACE", "name": "DatafileObject_v1", @@ -15407,12 +15241,12 @@ "possibleTypes": null }, { - "kind": "INTERFACE", - "name": "TerraformState_v1", + "kind": "OBJECT", + "name": "SqlEmailOverrides_v1", "description": null, "fields": [ { - "name": "provider", + "name": "db_host", "description": null, "args": [], "type": { @@ -15422,26 +15256,68 @@ }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ + }, { - "kind": "OBJECT", - "name": "TerraformStateAWS_v1", - "ofType": null + "name": "db_port", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "db_name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "db_user", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "db_password", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } - ] + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null }, { "kind": "OBJECT", - "name": "AWSTerraformStateIntegrations_v1", + "name": "GabiInstance_v1", "description": null, "fields": [ { - "name": "integration", + "name": "schema", "description": null, "args": [], "type": { @@ -15457,7 +15333,7 @@ "deprecationReason": null }, { - "name": "key", + "name": "path", "description": null, "args": [], "type": { @@ -15471,20 +15347,21 @@ }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RosaOcmSpec_v1", - "description": null, - "fields": [ + }, { - "name": "schema", + "name": "labels", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", "description": null, "args": [], "type": { @@ -15500,7 +15377,7 @@ "deprecationReason": null }, { - "name": "path", + "name": "description", "description": null, "args": [], "type": { @@ -15516,76 +15393,91 @@ "deprecationReason": null }, { - "name": "ocm_environments", + "name": "readReplicasWaiverPledge", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "signoffManagers", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "OBJECT", - "name": "RosaOcmAwsSpec_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User_v1", + "ofType": null + } } } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RosaOcmAwsSpec_v1", - "description": null, - "fields": [ + }, { - "name": "ocm", + "name": "users", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "OpenShiftClusterManager_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User_v1", + "ofType": null + } + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "creator_role_arn", + "name": "instances", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "GabiNamespace_v1", + "ofType": null + } + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "installer_role_arn", + "name": "expirationDate", "description": null, "args": [], "type": { @@ -15599,9 +15491,26 @@ }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [ { - "name": "support_role_arn", + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "GabiNamespace_v1", + "description": null, + "fields": [ + { + "name": "account", "description": null, "args": [], "type": { @@ -15617,27 +15526,31 @@ "deprecationReason": null }, { - "name": "controlplane_role_arn", + "name": "identifier", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "worker_role_arn", + "name": "namespace", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Namespace_v1", "ofType": null } }, @@ -15652,11 +15565,11 @@ }, { "kind": "OBJECT", - "name": "AWSQuotaLimits_v1", + "name": "Schedule_v1", "description": null, "fields": [ { - "name": "path", + "name": "schema", "description": null, "args": [], "type": { @@ -15672,7 +15585,7 @@ "deprecationReason": null }, { - "name": "schema", + "name": "path", "description": null, "args": [], "type": { @@ -15687,18 +15600,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "labels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "name", "description": null, @@ -15728,7 +15629,7 @@ "deprecationReason": null }, { - "name": "quotas", + "name": "schedule", "description": null, "args": [], "type": { @@ -15742,7 +15643,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "AWSQuota_v1", + "name": "ScheduleEntry_v1", "ofType": null } } @@ -15765,11 +15666,11 @@ }, { "kind": "OBJECT", - "name": "AWSQuota_v1", + "name": "ScheduleEntry_v1", "description": null, "fields": [ { - "name": "serviceCode", + "name": "start", "description": null, "args": [], "type": { @@ -15785,7 +15686,7 @@ "deprecationReason": null }, { - "name": "quotaCode", + "name": "end", "description": null, "args": [], "type": { @@ -15801,16 +15702,24 @@ "deprecationReason": null }, { - "name": "value", + "name": "users", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User_v1", + "ofType": null + } + } } }, "isDeprecated": false, @@ -15823,28 +15732,12 @@ "possibleTypes": null }, { - "kind": "OBJECT", - "name": "AWSOrganization_v1", + "kind": "INTERFACE", + "name": "AWSAccountSharingOption_v1", "description": null, "fields": [ { - "name": "payerAccount", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AWSAccount_v1", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ou", + "name": "provider", "description": null, "args": [], "type": { @@ -15860,15 +15753,15 @@ "deprecationReason": null }, { - "name": "tags", + "name": "account", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "JSON", + "kind": "OBJECT", + "name": "AWSAccount_v1", "ofType": null } }, @@ -15877,40 +15770,61 @@ } ], "inputFields": null, - "interfaces": [], + "interfaces": null, "enumValues": null, - "possibleTypes": null + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "AWSAccountSharingOptionAMI_v1", + "ofType": null + } + ] }, { - "kind": "OBJECT", - "name": "ExternalResourcesAccountSettings_v1", + "kind": "INTERFACE", + "name": "AWSAccountCleanupOption_v1", "description": null, "fields": [ { - "name": "channel", + "name": "provider", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, - "interfaces": [], + "interfaces": null, "enumValues": null, - "possibleTypes": null + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "AWSAccountCleanupOptionAMI_v1", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "AWSAccountCleanupOptionCloudWatch_v1", + "ofType": null + } + ] }, { "kind": "OBJECT", - "name": "AWSAccountRequest_v1", + "name": "TerraformStateAWS_v1", "description": null, "fields": [ { - "name": "path", + "name": "schema", "description": null, "args": [], "type": { @@ -15926,7 +15840,7 @@ "deprecationReason": null }, { - "name": "schema", + "name": "path", "description": null, "args": [], "type": { @@ -15942,19 +15856,7 @@ "deprecationReason": null }, { - "name": "labels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", + "name": "provider", "description": null, "args": [], "type": { @@ -15970,7 +15872,7 @@ "deprecationReason": null }, { - "name": "description", + "name": "bucket", "description": null, "args": [], "type": { @@ -15986,15 +15888,15 @@ "deprecationReason": null }, { - "name": "accountOwner", + "name": "region", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "Owner_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -16002,43 +15904,82 @@ "deprecationReason": null }, { - "name": "organization", + "name": "integrations", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "AWSOrganization_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AWSTerraformStateIntegrations_v1", + "ofType": null + } + } } }, "isDeprecated": false, "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "TerraformState_v1", + "ofType": null }, { - "name": "quotaLimits", + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INTERFACE", + "name": "TerraformState_v1", + "description": null, + "fields": [ + { + "name": "provider", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AWSQuotaLimits_v1", - "ofType": null - } - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ { - "name": "resourcesDefaultRegion", + "kind": "OBJECT", + "name": "TerraformStateAWS_v1", + "ofType": null + } + ] + }, + { + "kind": "OBJECT", + "name": "AWSTerraformStateIntegrations_v1", + "description": null, + "fields": [ + { + "name": "integration", "description": null, "args": [], "type": { @@ -16054,57 +15995,80 @@ "deprecationReason": null }, { - "name": "supportedDeploymentRegions", + "name": "key", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "RosaOcmSpec_v1", + "description": null, + "fields": [ { - "name": "uid", + "name": "schema", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "additionalFeatures", + "name": "path", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "accountFileTargetPath", + "name": "ocm_environments", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "RosaOcmAwsSpec_v1", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null @@ -16123,19 +16087,19 @@ }, { "kind": "OBJECT", - "name": "AWSECR_v1", + "name": "RosaOcmAwsSpec_v1", "description": null, "fields": [ { - "name": "schema", + "name": "ocm", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "OpenShiftClusterManager_v1", "ofType": null } }, @@ -16143,7 +16107,7 @@ "deprecationReason": null }, { - "name": "path", + "name": "creator_role_arn", "description": null, "args": [], "type": { @@ -16159,27 +16123,15 @@ "deprecationReason": null }, { - "name": "labels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "account", + "name": "installer_role_arn", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "AWSAccount_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -16187,7 +16139,7 @@ "deprecationReason": null }, { - "name": "name", + "name": "support_role_arn", "description": null, "args": [], "type": { @@ -16203,7 +16155,7 @@ "deprecationReason": null }, { - "name": "description", + "name": "controlplane_role_arn", "description": null, "args": [], "type": { @@ -16215,7 +16167,7 @@ "deprecationReason": null }, { - "name": "region", + "name": "worker_role_arn", "description": null, "args": [], "type": { @@ -16238,19 +16190,19 @@ }, { "kind": "OBJECT", - "name": "AWSInfrastructureManagementAccount_v1", + "name": "AWSQuotaLimits_v1", "description": null, "fields": [ { - "name": "account", + "name": "path", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "AWSAccount_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -16258,7 +16210,7 @@ "deprecationReason": null }, { - "name": "accessLevel", + "name": "schema", "description": null, "args": [], "type": { @@ -16274,30 +16226,19 @@ "deprecationReason": null }, { - "name": "default", + "name": "labels", "description": null, "args": [], "type": { "kind": "SCALAR", - "name": "Boolean", + "name": "JSON", "ofType": null }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ClusterPrometheus_v1", - "description": null, - "fields": [ + }, { - "name": "url", + "name": "name", "description": null, "args": [], "type": { @@ -16313,16 +16254,36 @@ "deprecationReason": null }, { - "name": "auth", + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "quotas", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "VaultSecret_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AWSQuota_v1", + "ofType": null + } + } } }, "isDeprecated": false, @@ -16330,17 +16291,23 @@ } ], "inputFields": null, - "interfaces": [], + "interfaces": [ + { + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "App_v1", + "name": "AWSQuota_v1", "description": null, "fields": [ { - "name": "schema", + "name": "serviceCode", "description": null, "args": [], "type": { @@ -16356,7 +16323,7 @@ "deprecationReason": null }, { - "name": "path", + "name": "quotaCode", "description": null, "args": [], "type": { @@ -16372,19 +16339,7 @@ "deprecationReason": null }, { - "name": "labels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", + "name": "value", "description": null, "args": [], "type": { @@ -16392,27 +16347,42 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Float", "ofType": null } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AWSOrganization_v1", + "description": null, + "fields": [ { - "name": "product", + "name": "payerAccount", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "Product_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AWSAccount_v1", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "description", + "name": "ou", "description": null, "args": [], "type": { @@ -16428,7 +16398,7 @@ "deprecationReason": null }, { - "name": "onboardingStatus", + "name": "tags", "description": null, "args": [], "type": { @@ -16436,39 +16406,49 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "JSON", "ofType": null } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ExternalResourcesAccountSettings_v1", + "description": null, + "fields": [ { - "name": "grafanaUrls", + "name": "channel", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "GrafanaDashboardUrls_v1", - "ofType": null - } - } - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AWSAccountRequest_v1", + "description": null, + "fields": [ { - "name": "sopsUrl", + "name": "path", "description": null, "args": [], "type": { @@ -16484,7 +16464,7 @@ "deprecationReason": null }, { - "name": "architectureDocument", + "name": "schema", "description": null, "args": [], "type": { @@ -16500,99 +16480,83 @@ "deprecationReason": null }, { - "name": "parentApp", + "name": "labels", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "App_v1", + "kind": "SCALAR", + "name": "JSON", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "serviceDocs", + "name": "name", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "serviceOwners", + "name": "description", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Owner_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "serviceNotifications", + "name": "accountOwner", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Owner_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "Owner_v1", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "dependencies", + "name": "organization", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Dependency_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "AWSOrganization_v1", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "gcrRepos", + "name": "quotaLimits", "description": null, "args": [], "type": { @@ -16603,7 +16567,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "AppGcrRepos_v1", + "name": "AWSQuotaLimits_v1", "ofType": null } } @@ -16612,27 +16576,23 @@ "deprecationReason": null }, { - "name": "artifactRegistryMirrors", + "name": "resourcesDefaultRegion", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppArtifactRegistryMirrors_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "quayRepos", + "name": "supportedDeploymentRegions", "description": null, "args": [], "type": { @@ -16642,8 +16602,8 @@ "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "AppQuayRepos_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } } @@ -16652,63 +16612,76 @@ "deprecationReason": null }, { - "name": "escalationPolicy", + "name": "uid", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppEscalationPolicy_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "endPoints", + "name": "additionalFeatures", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppEndPoints_v1", - "ofType": null - } - } + "kind": "SCALAR", + "name": "JSON", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "codeComponents", + "name": "accountFileTargetPath", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AWSECR_v1", + "description": null, + "fields": [ + { + "name": "schema", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppCodeComponents_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "appCode", + "name": "path", "description": null, "args": [], "type": { @@ -16724,192 +16697,170 @@ "deprecationReason": null }, { - "name": "costCenter", + "name": "labels", "description": null, "args": [], "type": { "kind": "SCALAR", - "name": "String", + "name": "JSON", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "statusPageComponents", + "name": "account", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "StatusPageComponent_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "AWSAccount_v1", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "namespaces", + "name": "name", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Namespace_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "childrenApps", + "name": "description", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "App_v1", - "ofType": null - } - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "jenkinsConfigs", + "name": "region", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "JenkinsConfig_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AWSInfrastructureManagementAccount_v1", + "description": null, + "fields": [ { - "name": "saasFiles", + "name": "account", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "SaasFile_v2", - "ofType": null - } + "kind": "OBJECT", + "name": "AWSAccount_v1", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "sreCheckpoints", + "name": "accessLevel", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "SRECheckpoint_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "sloDocuments", + "name": "default", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "SLODocument_v1", - "ofType": null - } - } + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ClusterPrometheus_v1", + "description": null, + "fields": [ { - "name": "glitchtipProjects", + "name": "url", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "GlitchtipProject_v1", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "selfServiceRoles", + "name": "auth", "description": null, "args": [], "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Role_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "VaultSecret_v1", + "ofType": null } }, "isDeprecated": false, @@ -16917,19 +16868,13 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "Product_v1", + "name": "App_v1", "description": null, "fields": [ { @@ -16992,6 +16937,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "product", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "Product_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "description", "description": null, @@ -17009,7 +16966,23 @@ "deprecationReason": null }, { - "name": "productOwners", + "name": "onboardingStatus", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "grafanaUrls", "description": null, "args": [], "type": { @@ -17023,7 +16996,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "Owner_v1", + "name": "GrafanaDashboardUrls_v1", "ofType": null } } @@ -17033,7 +17006,51 @@ "deprecationReason": null }, { - "name": "environments", + "name": "sopsUrl", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "architectureDocument", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "parentApp", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "App_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "serviceDocs", "description": null, "args": [], "type": { @@ -17043,8 +17060,8 @@ "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "Environment_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } } @@ -17053,7 +17070,7 @@ "deprecationReason": null }, { - "name": "apps", + "name": "serviceOwners", "description": null, "args": [], "type": { @@ -17064,113 +17081,116 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "App_v1", + "name": "Owner_v1", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Environment_v1", - "description": null, - "fields": [ + }, { - "name": "schema", + "name": "serviceNotifications", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Owner_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "path", + "name": "dependencies", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Dependency_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "labels", + "name": "gcrRepos", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppGcrRepos_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "name", + "name": "artifactRegistryMirrors", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppArtifactRegistryMirrors_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "description", + "name": "quayRepos", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppQuayRepos_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "product", + "name": "escalationPolicy", "description": null, "args": [], "type": { @@ -17178,7 +17198,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "Product_v1", + "name": "AppEscalationPolicy_v1", "ofType": null } }, @@ -17186,19 +17206,7 @@ "deprecationReason": null }, { - "name": "parameters", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "secretParameters", + "name": "endPoints", "description": null, "args": [], "type": { @@ -17209,7 +17217,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "SaasSecretParameters_v1", + "name": "AppEndPoints_v1", "ofType": null } } @@ -17218,19 +17226,27 @@ "deprecationReason": null }, { - "name": "dependsOn", + "name": "codeComponents", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "Environment_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppCodeComponents_v1", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "servicePhase", + "name": "appCode", "description": null, "args": [], "type": { @@ -17257,6 +17273,26 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "statusPageComponents", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "StatusPageComponent_v1", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "namespaces", "description": null, @@ -17276,144 +17312,141 @@ }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ + }, { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SaasSecretParameters_v1", - "description": null, - "fields": [ + "name": "childrenApps", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "App_v1", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { - "name": "name", + "name": "jenkinsConfigs", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "JenkinsConfig_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "secret", + "name": "saasFiles", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "OBJECT", - "name": "VaultSecret_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "SaasFile_v2", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GrafanaDashboardUrls_v1", - "description": null, - "fields": [ + }, { - "name": "title", + "name": "sreCheckpoints", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "SRECheckpoint_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "url", + "name": "sloDocuments", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "SLODocument_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AppGcrRepos_v1", - "description": null, - "fields": [ + }, { - "name": "project", + "name": "glitchtipProjects", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "OBJECT", - "name": "GcpProject_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "GlitchtipProject_v1", + "ofType": null + } } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "items", + "name": "selfServiceRoles", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppGcrReposItems_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "Role_v1", + "ofType": null } } }, @@ -17422,13 +17455,19 @@ } ], "inputFields": null, - "interfaces": [], + "interfaces": [ + { + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "GcpProject_v1", + "name": "Product_v1", "description": null, "fields": [ { @@ -17508,7 +17547,7 @@ "deprecationReason": null }, { - "name": "managedTeams", + "name": "productOwners", "description": null, "args": [], "type": { @@ -17521,8 +17560,8 @@ "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Owner_v1", "ofType": null } } @@ -17532,40 +17571,40 @@ "deprecationReason": null }, { - "name": "automationToken", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "VaultSecret_v1", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gcrPushCredentials", + "name": "environments", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "VaultSecret_v1", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Environment_v1", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "artifactPushCredentials", + "name": "apps", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "OBJECT", - "name": "VaultSecret_v1", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "App_v1", + "ofType": null + } } }, "isDeprecated": false, @@ -17574,11 +17613,6 @@ ], "inputFields": null, "interfaces": [ - { - "kind": "INTERFACE", - "name": "ExternalResourcesProvisioner_v1", - "ofType": null - }, { "kind": "INTERFACE", "name": "DatafileObject_v1", @@ -17590,11 +17624,11 @@ }, { "kind": "OBJECT", - "name": "AppGcrReposItems_v1", + "name": "Environment_v1", "description": null, "fields": [ { - "name": "name", + "name": "schema", "description": null, "args": [], "type": { @@ -17610,7 +17644,7 @@ "deprecationReason": null }, { - "name": "description", + "name": "path", "description": null, "args": [], "type": { @@ -17626,7 +17660,7 @@ "deprecationReason": null }, { - "name": "public", + "name": "labels", "description": null, "args": [], "type": { @@ -17634,7 +17668,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "Boolean", + "name": "JSON", "ofType": null } }, @@ -17642,30 +17676,7 @@ "deprecationReason": null }, { - "name": "mirror", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "ContainerImageMirror_v1", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ContainerImageMirror_v1", - "description": null, - "fields": [ - { - "name": "schema", + "name": "name", "description": null, "args": [], "type": { @@ -17681,7 +17692,7 @@ "deprecationReason": null }, { - "name": "path", + "name": "description", "description": null, "args": [], "type": { @@ -17697,15 +17708,15 @@ "deprecationReason": null }, { - "name": "url", + "name": "product", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Product_v1", "ofType": null } }, @@ -17713,19 +17724,19 @@ "deprecationReason": null }, { - "name": "pullCredentials", + "name": "parameters", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "VaultSecret_v1", + "kind": "SCALAR", + "name": "JSON", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "tags", + "name": "secretParameters", "description": null, "args": [], "type": { @@ -17735,8 +17746,8 @@ "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "SaasSecretParameters_v1", "ofType": null } } @@ -17745,52 +17756,27 @@ "deprecationReason": null }, { - "name": "tagsExclude", + "name": "dependsOn", "description": null, "args": [], "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } + "kind": "OBJECT", + "name": "Environment_v1", + "ofType": null }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AppArtifactRegistryMirrors_v1", - "description": null, - "fields": [ + }, { - "name": "project", + "name": "servicePhase", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "GcpProject_v1", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -17798,23 +17784,31 @@ "deprecationReason": null }, { - "name": "items", + "name": "costCenter", "description": null, "args": [], "type": { - "kind": "NON_NULL", + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "namespaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppArtifactRegistryMirrorsItems_v1", - "ofType": null - } + "kind": "OBJECT", + "name": "Namespace_v1", + "ofType": null } } }, @@ -17823,17 +17817,23 @@ } ], "inputFields": null, - "interfaces": [], + "interfaces": [ + { + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "AppArtifactRegistryMirrorsItems_v1", + "name": "SaasSecretParameters_v1", "description": null, "fields": [ { - "name": "imageURL", + "name": "name", "description": null, "args": [], "type": { @@ -17849,7 +17849,7 @@ "deprecationReason": null }, { - "name": "mirror", + "name": "secret", "description": null, "args": [], "type": { @@ -17857,7 +17857,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "ContainerImageMirror_v1", + "name": "VaultSecret_v1", "ofType": null } }, @@ -17872,11 +17872,11 @@ }, { "kind": "OBJECT", - "name": "AppQuayRepos_v1", + "name": "GrafanaDashboardUrls_v1", "description": null, "fields": [ { - "name": "path", + "name": "title", "description": null, "args": [], "type": { @@ -17892,7 +17892,7 @@ "deprecationReason": null }, { - "name": "schema", + "name": "url", "description": null, "args": [], "type": { @@ -17906,9 +17906,20 @@ }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AppGcrRepos_v1", + "description": null, + "fields": [ { - "name": "org", + "name": "project", "description": null, "args": [], "type": { @@ -17916,33 +17927,13 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "QuayOrg_v1", + "name": "GcpProject_v1", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, - { - "name": "teams", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "AppQuayReposTeams_v1", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "items", "description": null, @@ -17958,7 +17949,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "AppQuayReposItems_v1", + "name": "AppGcrReposItems_v1", "ofType": null } } @@ -17969,19 +17960,13 @@ } ], "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], + "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "QuayOrg_v1", + "name": "GcpProject_v1", "description": null, "fields": [ { @@ -18060,82 +18045,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "mirror", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "QuayOrg_v1", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mirrorFilters", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "QuayOrgMirrorFilter_v1", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "managedRepos", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instance", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "QuayInstance_v1", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "serverUrl", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "managedTeams", "description": null, @@ -18173,7 +18082,7 @@ "deprecationReason": null }, { - "name": "pushCredentials", + "name": "gcrPushCredentials", "description": null, "args": [], "type": { @@ -18183,10 +18092,31 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "artifactPushCredentials", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "VaultSecret_v1", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, "interfaces": [ + { + "kind": "INTERFACE", + "name": "ExternalResourcesProvisioner_v1", + "ofType": null + }, { "kind": "INTERFACE", "name": "DatafileObject_v1", @@ -18198,7 +18128,7 @@ }, { "kind": "OBJECT", - "name": "QuayOrgMirrorFilter_v1", + "name": "AppGcrReposItems_v1", "description": null, "fields": [ { @@ -18217,6 +18147,121 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "public", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mirror", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "ContainerImageMirror_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ContainerImageMirror_v1", + "description": null, + "fields": [ + { + "name": "schema", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "path", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pullCredentials", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "VaultSecret_v1", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "tags", "description": null, @@ -18259,25 +18304,31 @@ } ], "inputFields": null, - "interfaces": [], + "interfaces": [ + { + "kind": "INTERFACE", + "name": "DatafileObject_v1", + "ofType": null + } + ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", - "name": "QuayInstance_v1", + "name": "AppArtifactRegistryMirrors_v1", "description": null, "fields": [ { - "name": "schema", + "name": "project", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "GcpProject_v1", "ofType": null } }, @@ -18285,7 +18336,42 @@ "deprecationReason": null }, { - "name": "path", + "name": "items", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppArtifactRegistryMirrorsItems_v1", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AppArtifactRegistryMirrorsItems_v1", + "description": null, + "fields": [ + { + "name": "imageURL", "description": null, "args": [], "type": { @@ -18301,19 +18387,34 @@ "deprecationReason": null }, { - "name": "labels", + "name": "mirror", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ContainerImageMirror_v1", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AppQuayRepos_v1", + "description": null, + "fields": [ { - "name": "name", + "name": "path", "description": null, "args": [], "type": { @@ -18329,7 +18430,7 @@ "deprecationReason": null }, { - "name": "description", + "name": "schema", "description": null, "args": [], "type": { @@ -18345,20 +18446,64 @@ "deprecationReason": null }, { - "name": "url", + "name": "org", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "QuayOrg_v1", "ofType": null } }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "teams", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppQuayReposTeams_v1", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "items", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AppQuayReposItems_v1", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -18583,11 +18728,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -19184,11 +19324,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -27985,11 +28120,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -29551,11 +29681,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -32224,11 +32349,6 @@ "kind": "INTERFACE", "name": "FeatureToggle_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -51163,11 +51283,6 @@ "kind": "INTERFACE", "name": "PipelinesProvider_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -51903,11 +52018,6 @@ "kind": "INTERFACE", "name": "OidcPermission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -52073,11 +52183,6 @@ "kind": "INTERFACE", "name": "OidcPermission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -52215,11 +52320,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -52377,11 +52477,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -52563,11 +52658,6 @@ "kind": "INTERFACE", "name": "Permission_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -53629,232 +53719,7 @@ "deprecationReason": null }, { - "name": "blackboxExporter", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "EndpointMonitoringProviderBlackboxExporterSettings_v1", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "EndpointMonitoringProvider_v1", - "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EndpointMonitoringProviderBlackboxExporterSettings_v1", - "description": null, - "fields": [ - { - "name": "module", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "namespace", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Namespace_v1", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "exporterUrl", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EndpointMonitoringProviderSignalFx_v1", - "description": null, - "fields": [ - { - "name": "schema", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "path", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "labels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "provider", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metricLabels", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timeout", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "checkInterval", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "signalFx", + "name": "blackboxExporter", "description": null, "args": [], "type": { @@ -53862,7 +53727,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "EndpointMonitoringProviderSignalFxSettings_v1", + "name": "EndpointMonitoringProviderBlackboxExporterSettings_v1", "ofType": null } }, @@ -53876,10 +53741,225 @@ "kind": "INTERFACE", "name": "EndpointMonitoringProvider_v1", "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "EndpointMonitoringProviderBlackboxExporterSettings_v1", + "description": null, + "fields": [ + { + "name": "module", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "namespace", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Namespace_v1", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "exporterUrl", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "EndpointMonitoringProviderSignalFx_v1", + "description": null, + "fields": [ + { + "name": "schema", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "path", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "labels", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "provider", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "metricLabels", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "timeout", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "checkInterval", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null }, + { + "name": "signalFx", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "EndpointMonitoringProviderSignalFxSettings_v1", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ { "kind": "INTERFACE", - "name": "DatafileObject_v1", + "name": "EndpointMonitoringProvider_v1", "ofType": null } ], @@ -54769,11 +54849,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -54946,11 +55021,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -55112,11 +55182,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -55321,11 +55386,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -55487,11 +55547,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -55629,11 +55684,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -55795,11 +55845,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -56004,11 +56049,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, @@ -56241,11 +56281,6 @@ "kind": "INTERFACE", "name": "AutomatedAction_v1", "ofType": null - }, - { - "kind": "INTERFACE", - "name": "DatafileObject_v1", - "ofType": null } ], "enumValues": null, diff --git a/reconcile/gql_definitions/quay_robot_accounts/__init__.py b/reconcile/gql_definitions/quay_robot_accounts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.gql b/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.gql new file mode 100644 index 0000000000..f6fa2db189 --- /dev/null +++ b/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.gql @@ -0,0 +1,25 @@ +# qenerate: plugin=pydantic_v1 + +query QuayRobotAccounts { + robot_accounts: quay_robots_v1 { + name + description + quay_org { + name + instance { + name + url + } + automationToken { + path + field + version + } + } + teams + repositories { + name + permission + } + } +} \ No newline at end of file diff --git a/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.py b/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.py new file mode 100644 index 0000000000..2858f79176 --- /dev/null +++ b/reconcile/gql_definitions/quay_robot_accounts/quay_robot_accounts.py @@ -0,0 +1,104 @@ +""" +Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY! +""" +from collections.abc import Callable # noqa: F401 # pylint: disable=W0611 +from datetime import datetime # noqa: F401 # pylint: disable=W0611 +from enum import Enum # noqa: F401 # pylint: disable=W0611 +from typing import ( # noqa: F401 # pylint: disable=W0611 + Any, + Optional, + Union, +) + +from pydantic import ( # noqa: F401 # pylint: disable=W0611 + BaseModel, + Extra, + Field, + Json, +) + + +DEFINITION = """ +query QuayRobotAccounts { + robot_accounts: quay_robots_v1 { + name + description + quay_org { + name + instance { + name + url + } + automationToken { + path + field + version + } + } + teams + repositories { + name + permission + } + } +} +""" + + +class ConfiguredBaseModel(BaseModel): + class Config: + smart_union=True + extra=Extra.forbid + + +class QuayInstanceV1(ConfiguredBaseModel): + name: str = Field(..., alias="name") + url: str = Field(..., alias="url") + + +class VaultSecretV1(ConfiguredBaseModel): + path: str = Field(..., alias="path") + field: str = Field(..., alias="field") + version: Optional[int] = Field(..., alias="version") + + +class QuayOrgV1(ConfiguredBaseModel): + name: str = Field(..., alias="name") + instance: QuayInstanceV1 = Field(..., alias="instance") + automation_token: Optional[VaultSecretV1] = Field(..., alias="automationToken") + + +class QuayRepositoryV1(ConfiguredBaseModel): + name: str = Field(..., alias="name") + permission: str = Field(..., alias="permission") + + +class QuayRobotV1(ConfiguredBaseModel): + name: str = Field(..., alias="name") + description: Optional[str] = Field(..., alias="description") + quay_org: Optional[QuayOrgV1] = Field(..., alias="quay_org") + teams: Optional[list[str]] = Field(..., alias="teams") + repositories: Optional[list[QuayRepositoryV1]] = Field(..., alias="repositories") + + +class QuayRobotAccountsQueryData(ConfiguredBaseModel): + robot_accounts: Optional[list[QuayRobotV1]] = Field(..., alias="robot_accounts") + + +def query(query_func: Callable, **kwargs: Any) -> QuayRobotAccountsQueryData: + """ + This is a convenience function which queries and parses the data into + concrete types. It should be compatible with most GQL clients. + You do not have to use it to consume the generated data classes. + Alternatively, you can also mime and alternate the behavior + of this function in the caller. + + Parameters: + query_func (Callable): Function which queries your GQL Server + kwargs: optional arguments that will be passed to the query function + + Returns: + QuayRobotAccountsQueryData: queried data parsed into generated classes + """ + raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs) + return QuayRobotAccountsQueryData(**raw_data) diff --git a/reconcile/quay_base.py b/reconcile/quay_base.py index eaafa06079..499ca6941e 100644 --- a/reconcile/quay_base.py +++ b/reconcile/quay_base.py @@ -34,7 +34,7 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: self.cleanup() -def get_quay_api_store() -> dict[OrgKey, OrgInfo]: +def get_quay_api_store() -> QuayApiStore: """ Returns a dictionary with a key for each Quay organization managed in app-interface. @@ -42,7 +42,7 @@ def get_quay_api_store() -> dict[OrgKey, OrgInfo]: quay_orgs = queries.get_quay_orgs() settings = queries.get_app_interface_settings() secret_reader = SecretReader(settings=settings) - store = {} + store = QuayApiStore() for org_data in quay_orgs: instance_name = org_data["instance"]["name"] org_name = org_data["name"] diff --git a/reconcile/quay_robot_accounts.py b/reconcile/quay_robot_accounts.py new file mode 100644 index 0000000000..6cc0ad6e24 --- /dev/null +++ b/reconcile/quay_robot_accounts.py @@ -0,0 +1,399 @@ +import logging +from dataclasses import dataclass +from enum import Enum + +from reconcile.gql_definitions.quay_robot_accounts.quay_robot_accounts import ( + QuayRobotV1, + query, +) +from reconcile.quay_base import QuayApiStore, get_quay_api_store +from reconcile.utils import gql +from reconcile.utils.quay_api import RobotAccountDetails + +QONTRACT_INTEGRATION = "quay-robot-accounts" + + +class RobotAccountActionType(Enum): + CREATE = "create" + DELETE = "delete" + ADD_TEAM = "add_team" + REMOVE_TEAM = "remove_team" + SET_REPO_PERMISSION = "set_repo_permission" + REMOVE_REPO_PERMISSION = "remove_repo_permission" + + +@dataclass +class RobotAccountState: + """Represents the state of a robot account""" + + name: str + description: str | None + org_name: str + instance_name: str + teams: set[str] + repositories: dict[str, str] # repo_name -> permission + + +@dataclass +class RobotAccountAction: + """Represents an action to be performed on a robot account""" + + action: RobotAccountActionType + robot_name: str + org_name: str + instance_name: str + team: str | None = None + repo: str | None = None + permission: str | None = None + + +def get_robot_accounts_from_gql() -> list[QuayRobotV1]: + """Fetch robot account definitions from GraphQL""" + query_data = query(query_func=gql.get_api().query) + return list(query_data.robot_accounts or []) + + +def get_current_robot_accounts( + quay_api_store: QuayApiStore, +) -> dict[tuple[str, str], list[RobotAccountDetails]]: + """Fetch current robot accounts from Quay API for all organizations""" + current_state = {} + + for org_key, org_info in quay_api_store.items(): + try: + robots = org_info["api"].list_robot_accounts() + current_state[org_key.instance, org_key.org_name] = robots or [] + except Exception as e: + logging.error( + f"Failed to fetch robot accounts for {org_key.instance}/{org_key.org_name}: {e}" + ) + current_state[org_key.instance, org_key.org_name] = [] + + return current_state + + +def build_desired_state( + robot_accounts: list[QuayRobotV1], +) -> dict[tuple[str, str, str], RobotAccountState]: + """Build desired state from GraphQL definitions""" + desired_state = {} + + for robot in robot_accounts: + if not robot.quay_org: + continue + + instance_name = robot.quay_org.instance.name + org_name = robot.quay_org.name + robot_name = robot.name + + teams = set(robot.teams or []) + repositories = {} + + if robot.repositories: + for repo in robot.repositories: + repositories[repo.name] = repo.permission + + state = RobotAccountState( + name=robot_name, + description=robot.description, + org_name=org_name, + instance_name=instance_name, + teams=teams, + repositories=repositories, + ) + + desired_state[instance_name, org_name, robot_name] = state + + return desired_state + + +def build_current_state( + current_robots: dict[tuple[str, str], list[RobotAccountDetails]], + quay_api_store: QuayApiStore, +) -> dict[tuple[str, str, str], RobotAccountState]: + """Build current state from Quay API data""" + current_state = {} + + for (instance_name, org_name), robots in current_robots.items(): + org_key = next( + ( + k + for k in quay_api_store + if k.instance == instance_name and k.org_name == org_name + ), + None, + ) + + if not org_key: + continue + + for robot_data in robots: + robot_name = robot_data["name"] + description = robot_data.get("description") + + # Get team memberships + team_permissions = robot_data.get("teams", []) + teams = {team_perm["name"] for team_perm in team_permissions} + + # Get repository permissions + repositories = {} + repo_permissions = robot_data.get("repositories", []) + for repo_perm in repo_permissions: + repositories[repo_perm["name"]] = repo_perm["role"] + + state = RobotAccountState( + name=robot_name, + description=description, + org_name=org_name, + instance_name=instance_name, + teams=teams, + repositories=repositories, + ) + + current_state[instance_name, org_name, robot_name] = state + + return current_state + + +def calculate_diff( + desired_state: dict[tuple[str, str, str], RobotAccountState], + current_state: dict[tuple[str, str, str], RobotAccountState], +) -> list[RobotAccountAction]: + """Calculate the differences between desired and current state""" + actions = [] + + # Find robots to create + for key, desired in desired_state.items(): + if key not in current_state: + actions.append( + RobotAccountAction( + action=RobotAccountActionType.CREATE, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + ) + ) + + # Add team assignments for new robot + actions.extend([ + RobotAccountAction( + action=RobotAccountActionType.ADD_TEAM, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + team=team, + ) + for team in desired.teams + ]) + + # Add repository permissions for new robot + actions.extend([ + RobotAccountAction( + action=RobotAccountActionType.SET_REPO_PERMISSION, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + repo=repo, + permission=permission, + ) + for repo, permission in desired.repositories.items() + ]) + else: + current = current_state[key] + + # Check team differences + teams_to_add = desired.teams - current.teams + teams_to_remove = current.teams - desired.teams + + actions.extend([ + RobotAccountAction( + action=RobotAccountActionType.ADD_TEAM, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + team=team, + ) + for team in teams_to_add + ]) + + actions.extend([ + RobotAccountAction( + action=RobotAccountActionType.REMOVE_TEAM, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + team=team, + ) + for team in teams_to_remove + ]) + + # Check repository permission differences + desired_repos = set(desired.repositories.keys()) + current_repos = set(current.repositories.keys()) + + # Repositories to add or update permissions + actions.extend( + RobotAccountAction( + action=RobotAccountActionType.SET_REPO_PERMISSION, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + repo=repo, + permission=desired.repositories[repo], + ) + for repo in desired_repos + if repo not in current_repos + or desired.repositories[repo] != current.repositories.get(repo) + ) + + # Repositories to remove permissions from + repos_to_remove = current_repos - desired_repos + actions.extend([ + RobotAccountAction( + action=RobotAccountActionType.REMOVE_REPO_PERMISSION, + robot_name=desired.name, + org_name=desired.org_name, + instance_name=desired.instance_name, + repo=repo, + ) + for repo in repos_to_remove + ]) + + # Find robots to delete (robots in current state but not in desired state) + for key, current in current_state.items(): + if key not in desired_state: + actions.append( + RobotAccountAction( + action=RobotAccountActionType.DELETE, + robot_name=current.name, + org_name=current.org_name, + instance_name=current.instance_name, + ) + ) + + return actions + + +def apply_action( + action: RobotAccountAction, + quay_api_store: QuayApiStore, + dry_run: bool = False, +) -> None: + """Apply a single action to Quay""" + org_key = next( + ( + k + for k in quay_api_store + if k.instance == action.instance_name and k.org_name == action.org_name + ), + None, + ) + + if not org_key: + logging.error(f"No API found for {action.instance_name}/{action.org_name}") + return + + quay_api = quay_api_store[org_key]["api"] + + if dry_run: + logging.info(f"[DRY RUN] Would perform: {action}") + return + + match action.action: + case RobotAccountActionType.CREATE: + logging.info( + f"Creating robot account {action.robot_name} in {action.org_name}" + ) + quay_api.create_robot_account(action.robot_name, "") + + case RobotAccountActionType.DELETE: + logging.info( + f"Deleting robot account {action.robot_name} from {action.org_name}" + ) + quay_api.delete_robot_account(action.robot_name) + + case RobotAccountActionType.ADD_TEAM: + logging.info( + f"Adding robot {action.robot_name} to team {action.team} in {action.org_name}" + ) + if not action.team: + raise ValueError(f"Team is required for add_team action: {action}") + quay_api.add_user_to_team( + f"{action.org_name}+{action.robot_name}", action.team + ) + + case RobotAccountActionType.REMOVE_TEAM: + logging.info( + f"Removing robot {action.robot_name} from team {action.team} in {action.org_name}" + ) + if not action.team: + raise ValueError(f"Team is required for remove_team action: {action}") + quay_api.remove_user_from_team( + f"{action.org_name}+{action.robot_name}", action.team + ) + + case RobotAccountActionType.SET_REPO_PERMISSION: + logging.info( + f"Setting {action.permission} permission for robot {action.robot_name} on repo {action.repo}" + ) + if not action.repo: + raise ValueError( + f"Repo is required for set_repo_permission action: {action}" + ) + if not action.permission: + raise ValueError( + f"Permission is required for set_repo_permission action: {action}" + ) + quay_api.set_repo_robot_account_permissions( + action.repo, action.robot_name, action.permission + ) + + case RobotAccountActionType.REMOVE_REPO_PERMISSION: + logging.info( + f"Removing permissions for robot {action.robot_name} from repo {action.repo}" + ) + if not action.repo: + raise ValueError( + f"Repo is required for set_repo_permissions action: {action}" + ) + quay_api.delete_repo_robot_account_permissions( + action.repo, action.robot_name + ) + + +def run(dry_run: bool = False) -> None: + """Main function to run the integration""" + # Get GraphQL data + robot_accounts = get_robot_accounts_from_gql() + logging.debug(f"Found {len(robot_accounts)} robot account definitions") + + # Get Quay API store + quay_api_store = get_quay_api_store() + + # Get current state from Quay + current_robots = get_current_robot_accounts(quay_api_store) + + # Build states + desired_state = build_desired_state(robot_accounts) + current_state = build_current_state(current_robots, quay_api_store) + + logging.debug(f"Desired robots: {len(desired_state)}") + logging.debug(f"Current robots: {len(current_state)}") + + # Calculate diff + actions = calculate_diff(desired_state, current_state) + + if not actions: + logging.debug("No actions needed") + return + + logging.debug(f"Found {len(actions)} actions to perform") + + if dry_run: + logging.debug("Running in dry-run mode - no changes will be made") + + # Apply actions + for action in actions: + apply_action(action, quay_api_store, dry_run) + + logging.debug("Integration completed successfully") diff --git a/reconcile/test/test_quay_mirror_org.py b/reconcile/test/test_quay_mirror_org.py index 395e9d3b92..45fc1531f2 100644 --- a/reconcile/test/test_quay_mirror_org.py +++ b/reconcile/test/test_quay_mirror_org.py @@ -22,15 +22,16 @@ @patch("reconcile.utils.gql.get_api", autospec=True) @patch("reconcile.queries.get_app_interface_settings", return_value={}) +@patch("reconcile.quay_base.get_quay_api_store", return_value={}) class TestControlFile: def test_control_file_dir_does_not_exist( - self, mock_gql: Mock, mock_settings: Mock + self, mock_gql: Mock, mock_settings: Mock, mock_quay_api_store: Mock ) -> None: with pytest.raises(FileNotFoundError): QuayMirrorOrg(control_file_dir="/no-such-dir") def test_control_file_path_from_given_dir( - self, mock_gql: Mock, mock_settings: Mock + self, mock_gql: Mock, mock_settings: Mock, mock_quay_api_store: Mock ) -> None: with tempfile.TemporaryDirectory() as tmp_dir_name: qm = QuayMirrorOrg(control_file_dir=tmp_dir_name) @@ -39,6 +40,7 @@ def test_control_file_path_from_given_dir( @patch("reconcile.utils.gql.get_api", autospec=True) @patch("reconcile.queries.get_app_interface_settings", return_value={}) +@patch("reconcile.quay_base.get_quay_api_store", return_value={}) @patch("time.time", return_value=NOW) class TestIsCompareTags: def setup_method(self) -> None: @@ -53,14 +55,22 @@ def teardown_method(self) -> None: # Last run was in NOW - 100s, we run compare tags every 10s. def test_is_compare_tags_elapsed( - self, mock_gql: Mock, mock_settings: Mock, mock_time: Mock + self, + mock_gql: Mock, + mock_settings: Mock, + mock_time: Mock, + mock_quay_api_store: Mock, ) -> None: qm = QuayMirrorOrg(control_file_dir=self.tmp_dir.name, compare_tags_interval=10) assert qm.is_compare_tags # Same as before, but now we force no compare with the option. def test_is_compare_tags_force_no_compare( - self, mock_gql: Mock, mock_settings: Mock, mock_time: Mock + self, + mock_gql: Mock, + mock_settings: Mock, + mock_time: Mock, + mock_quay_api_store: Mock, ) -> None: qm = QuayMirrorOrg( control_file_dir=self.tmp_dir.name, @@ -71,7 +81,11 @@ def test_is_compare_tags_force_no_compare( # Last run was in NOW - 100s, we run compare tags every 1000s. def test_is_compare_tags_not_elapsed( - self, mock_gql: Mock, mock_settings: Mock, mock_time: Mock + self, + mock_gql: Mock, + mock_settings: Mock, + mock_time: Mock, + mock_quay_api_store: Mock, ) -> None: qm = QuayMirrorOrg( control_file_dir=self.tmp_dir.name, compare_tags_interval=1000 @@ -80,7 +94,11 @@ def test_is_compare_tags_not_elapsed( # Same as before, but now we force compare with the option. def test_is_compare_tags_force_compare( - self, mock_gql: Mock, mock_settings: Mock, mock_time: Mock + self, + mock_gql: Mock, + mock_settings: Mock, + mock_time: Mock, + mock_quay_api_store: Mock, ) -> None: qm = QuayMirrorOrg( control_file_dir=self.tmp_dir.name, diff --git a/reconcile/test/test_quay_robot_accounts.py b/reconcile/test/test_quay_robot_accounts.py new file mode 100644 index 0000000000..f26d05b475 --- /dev/null +++ b/reconcile/test/test_quay_robot_accounts.py @@ -0,0 +1,522 @@ +from unittest.mock import create_autospec + +import pytest + +from reconcile.gql_definitions.quay_robot_accounts.quay_robot_accounts import ( + QuayInstanceV1, + QuayOrgV1, + QuayRepositoryV1, + QuayRobotV1, + VaultSecretV1, +) +from reconcile.quay_base import OrgInfo, OrgKey, QuayApiStore +from reconcile.quay_robot_accounts import ( + RobotAccountAction, + RobotAccountActionType, + RobotAccountState, + apply_action, + build_current_state, + build_desired_state, + calculate_diff, + get_current_robot_accounts, +) +from reconcile.utils.quay_api import QuayApi, RobotAccountDetails + + +@pytest.fixture +def mock_robot_gql() -> QuayRobotV1: + """Mock robot account from GraphQL""" + return QuayRobotV1( + name="test-robot", + description="Test robot account", + quay_org=QuayOrgV1( + name="test-org", + instance=QuayInstanceV1(name="quay-instance", url="quay.io"), + automationToken=VaultSecretV1(path="path", field="field", version=1), + ), + teams=["team1", "team2"], + repositories=[ + QuayRepositoryV1(name="repo1", permission="read"), + QuayRepositoryV1(name="repo2", permission="write"), + ], + ) + + +@pytest.fixture +def mock_current_robot() -> RobotAccountDetails: + """Mock current robot account from Quay API""" + return RobotAccountDetails( + name="existing-robot", + description="Existing robot", + teams=[{"name": "team1"}], + repositories=[{"name": "repo1", "role": "read"}], + ) + + +@pytest.fixture +def mock_quay_api() -> QuayApi: + """Mock QuayApi""" + return create_autospec(QuayApi) + + +@pytest.fixture +def mock_quay_api_store(mock_quay_api: QuayApi) -> dict[OrgKey, OrgInfo]: + """Mock QuayApiStore""" + return { + OrgKey("quay-instance", "test-org"): OrgInfo( + url="quay.io", + push_token=None, + teams=[], + managedRepos=False, + mirror=None, + mirror_filters={}, + api=mock_quay_api, + ) + } + + +def test_build_desired_state_single_robot(mock_robot_gql: QuayRobotV1) -> None: + """Test building desired state with a single robot""" + robots = [mock_robot_gql] + desired_state = build_desired_state(robots) + + assert len(desired_state) == 1 + key = ("quay-instance", "test-org", "test-robot") + assert key in desired_state + + state = desired_state[key] + assert state.name == "test-robot" + assert state.description == "Test robot account" + assert state.org_name == "test-org" + assert state.instance_name == "quay-instance" + assert state.teams == {"team1", "team2"} + assert state.repositories == {"repo1": "read", "repo2": "write"} + + +def test_build_desired_state_no_quay_org(mock_robot_gql: QuayRobotV1) -> None: + """Test building desired state with robot without quay_org""" + robot = QuayRobotV1( + name="test-robot", + description="Test robot", + quay_org=None, + teams=[], + repositories=[], + ) + + desired_state = build_desired_state([robot]) + assert len(desired_state) == 0 + + +def test_build_desired_state_empty_teams_repos(mock_robot_gql: QuayRobotV1) -> None: + """Test building desired state with empty teams and repositories""" + robot = QuayRobotV1( + name="test-robot", + description="Test robot", + quay_org=QuayOrgV1( + name="test-org", + instance=QuayInstanceV1(name="quay-instance", url="quay.io"), + automationToken=None, + ), + teams=None, + repositories=None, + ) + + desired_state = build_desired_state([robot]) + key = ("quay-instance", "test-org", "test-robot") + state = desired_state[key] + + assert state.teams == set() + assert state.repositories == {} + + +def test_build_current_state_single_robot( + mock_current_robot: RobotAccountDetails, mock_quay_api_store: QuayApiStore +) -> None: + """Test building current state with a single robot""" + current_robots = {("quay-instance", "test-org"): [mock_current_robot]} + + current_state = build_current_state(current_robots, mock_quay_api_store) + + assert len(current_state) == 1 + key = ("quay-instance", "test-org", "existing-robot") + assert key in current_state + + state = current_state[key] + assert state.name == "existing-robot" + assert state.description == "Existing robot" + assert state.teams == {"team1"} + assert state.repositories == {"repo1": "read"} + + +def test_build_current_state_no_org_key( + mock_current_robot: RobotAccountDetails, mock_quay_api_store: QuayApiStore +) -> None: + """Test building current state with no matching org key""" + current_robots = {("unknown-instance", "unknown-org"): [mock_current_robot]} + + current_state = build_current_state(current_robots, mock_quay_api_store) + assert len(current_state) == 0 + + +def test_build_current_state_empty_robots(mock_quay_api_store: QuayApiStore) -> None: + """Test building current state with empty robot list""" + current_robots: dict[tuple[str, str], list[RobotAccountDetails]] = { + ("quay-instance", "test-org"): [] + } + + current_state = build_current_state(current_robots, mock_quay_api_store) + assert len(current_state) == 0 + + +def test_calculate_diff_create_robot() -> None: + """Test calculating diff when robot needs to be created""" + desired_state = { + ("instance", "org", "new-robot"): RobotAccountState( + name="new-robot", + description="New robot", + org_name="org", + instance_name="instance", + teams={"team1"}, + repositories={"repo1": "read"}, + ) + } + current_state: dict[tuple[str, str, str], RobotAccountState] = {} + + actions = calculate_diff(desired_state, current_state) + + assert len(actions) == 3 # create, add_team, set_repo_permission + + create_action = next( + a for a in actions if a.action == RobotAccountActionType.CREATE + ) + assert create_action.robot_name == "new-robot" + assert create_action.org_name == "org" + + team_action = next( + a for a in actions if a.action == RobotAccountActionType.ADD_TEAM + ) + assert team_action.team == "team1" + + repo_action = next( + a for a in actions if a.action == RobotAccountActionType.SET_REPO_PERMISSION + ) + assert repo_action.repo == "repo1" + assert repo_action.permission == "read" + + +def test_calculate_diff_delete_robot() -> None: + """Test calculating diff when robot needs to be deleted""" + desired_state: dict[tuple[str, str, str], RobotAccountState] = {} + current_state = { + ("instance", "org", "old-robot"): RobotAccountState( + name="old-robot", + description="Old robot", + org_name="org", + instance_name="instance", + teams=set(), + repositories={}, + ) + } + + actions = calculate_diff(desired_state, current_state) + + assert len(actions) == 1 + assert actions[0].action == RobotAccountActionType.DELETE + assert actions[0].robot_name == "old-robot" + + +def test_calculate_diff_team_changes() -> None: + """Test calculating diff for team membership changes""" + desired_state = { + ("instance", "org", "robot"): RobotAccountState( + name="robot", + description="Robot", + org_name="org", + instance_name="instance", + teams={"team1", "team3"}, # remove team2, add team3 + repositories={}, + ) + } + current_state = { + ("instance", "org", "robot"): RobotAccountState( + name="robot", + description="Robot", + org_name="org", + instance_name="instance", + teams={"team1", "team2"}, # has team2, missing team3 + repositories={}, + ) + } + + actions = calculate_diff(desired_state, current_state) + + action_types = [a.action for a in actions] + assert RobotAccountActionType.ADD_TEAM in action_types + assert RobotAccountActionType.REMOVE_TEAM in action_types + + add_action = next(a for a in actions if a.action == RobotAccountActionType.ADD_TEAM) + assert add_action.team == "team3" + + remove_action = next( + a for a in actions if a.action == RobotAccountActionType.REMOVE_TEAM + ) + assert remove_action.team == "team2" + + +def test_calculate_diff_repository_changes() -> None: + """Test calculating diff for repository permission changes""" + desired_state = { + ("instance", "org", "robot"): RobotAccountState( + name="robot", + description="Robot", + org_name="org", + instance_name="instance", + teams=set(), + repositories={ + "repo1": "write", + "repo3": "read", + }, # change repo1, add repo3, remove repo2 + ) + } + current_state = { + ("instance", "org", "robot"): RobotAccountState( + name="robot", + description="Robot", + org_name="org", + instance_name="instance", + teams=set(), + repositories={ + "repo1": "read", + "repo2": "write", + }, # repo1 has different permission, repo2 should be removed + ) + } + + actions = calculate_diff(desired_state, current_state) + + action_types = [a.action for a in actions] + assert RobotAccountActionType.SET_REPO_PERMISSION in action_types + assert RobotAccountActionType.REMOVE_REPO_PERMISSION in action_types + + set_actions = [ + a for a in actions if a.action == RobotAccountActionType.SET_REPO_PERMISSION + ] + assert len(set_actions) == 2 # repo1 permission change, repo3 new + + remove_action = next( + a for a in actions if a.action == RobotAccountActionType.REMOVE_REPO_PERMISSION + ) + assert remove_action.repo == "repo2" + + +def test_calculate_diff_no_changes() -> None: + """Test calculating diff when no changes are needed""" + state = RobotAccountState( + name="robot", + description="Robot", + org_name="org", + instance_name="instance", + teams={"team1"}, + repositories={"repo1": "read"}, + ) + desired_state = {("instance", "org", "robot"): state} + current_state = {("instance", "org", "robot"): state} + + actions = calculate_diff(desired_state, current_state) + assert len(actions) == 0 + + +def test_get_current_robot_accounts_success( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test successful fetching of current robot accounts""" + mock_robots = [ + RobotAccountDetails( + name="robot1", + description="Robot 1", + teams=[{"name": "team1"}], + repositories=[{"name": "repo1", "role": "read"}], + ), + RobotAccountDetails( + name="robot2", + description="Robot 2", + teams=[{"name": "team2"}], + repositories=[{"name": "repo2", "role": "write"}], + ), + ] + + mock_quay_api.list_robot_accounts.return_value = mock_robots # type: ignore + + result = get_current_robot_accounts(mock_quay_api_store) + + assert len(result) == 1 + assert ("quay-instance", "test-org") in result + assert result["quay-instance", "test-org"] == mock_robots + + +def test_get_current_robot_accounts_exception( + mock_quay_api: QuayApi, + mock_quay_api_store: QuayApiStore, +) -> None: + """Test handling of exceptions when fetching robot accounts""" + mock_quay_api.list_robot_accounts.side_effect = Exception("API Error") # type: ignore + + result = get_current_robot_accounts(mock_quay_api_store) + + assert len(result) == 1 + assert result["quay-instance", "test-org"] == [] + + +def test_apply_action_create_robot( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying create robot action""" + action = RobotAccountAction( + action=RobotAccountActionType.CREATE, + robot_name="new-robot", + org_name="test-org", + instance_name="quay-instance", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.create_robot_account.assert_called_once_with("new-robot", "") # type: ignore + + +def test_apply_action_delete_robot( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying delete robot action""" + action = RobotAccountAction( + action=RobotAccountActionType.DELETE, + robot_name="old-robot", + org_name="test-org", + instance_name="quay-instance", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.delete_robot_account.assert_called_once_with("old-robot") # type: ignore + + +def test_apply_action_add_team( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying add team action""" + action = RobotAccountAction( + action=RobotAccountActionType.ADD_TEAM, + robot_name="robot", + org_name="test-org", + instance_name="quay-instance", + team="new-team", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.add_user_to_team.assert_called_once_with("test-org+robot", "new-team") # type: ignore + + +def test_apply_action_remove_team( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying remove team action""" + action = RobotAccountAction( + action=RobotAccountActionType.REMOVE_TEAM, + robot_name="robot", + org_name="test-org", + instance_name="quay-instance", + team="old-team", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.remove_user_from_team.assert_called_once_with( # type: ignore + "test-org+robot", "old-team" + ) + + +def test_apply_action_set_repo_permission( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying set repository permission action""" + action = RobotAccountAction( + action=RobotAccountActionType.SET_REPO_PERMISSION, + robot_name="robot", + org_name="test-org", + instance_name="quay-instance", + repo="repo1", + permission="write", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.set_repo_robot_account_permissions.assert_called_once_with( # type: ignore + "repo1", "robot", "write" + ) + + +def test_apply_action_remove_repo_permission( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying remove repository permission action""" + action = RobotAccountAction( + action=RobotAccountActionType.REMOVE_REPO_PERMISSION, + robot_name="robot", + org_name="test-org", + instance_name="quay-instance", + repo="repo1", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.delete_repo_robot_account_permissions.assert_called_once_with( # type: ignore + "repo1", "robot" + ) + + +def test_apply_action_dry_run( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying action in dry run mode""" + action = RobotAccountAction( + action=RobotAccountActionType.CREATE, + robot_name="new-robot", + org_name="test-org", + instance_name="quay-instance", + ) + + apply_action(action, mock_quay_api_store, dry_run=True) + + mock_quay_api.create_robot_account.assert_not_called() # type: ignore + + +def test_apply_action_no_org_key( + mock_quay_api: QuayApi, mock_quay_api_store: QuayApiStore +) -> None: + """Test applying action when org key is not found""" + action = RobotAccountAction( + action=RobotAccountActionType.CREATE, + robot_name="new-robot", + org_name="unknown-org", + instance_name="unknown-instance", + ) + + apply_action(action, mock_quay_api_store, dry_run=False) + + mock_quay_api.create_robot_account.assert_not_called() # type: ignore + + +def test_apply_action_exception_handling(mock_quay_api_store: QuayApiStore) -> None: + """Test exception handling in apply_action""" + mock_api = mock_quay_api_store[next(iter(mock_quay_api_store.keys()))]["api"] + mock_api.create_robot_account.side_effect = Exception("API Error") # type: ignore + + action = RobotAccountAction( + action=RobotAccountActionType.CREATE, + robot_name="new-robot", + org_name="test-org", + instance_name="quay-instance", + ) + + with pytest.raises(Exception, match="API Error"): + apply_action(action, mock_quay_api_store, dry_run=False) diff --git a/reconcile/test/utils/test_quay_api.py b/reconcile/test/utils/test_quay_api.py index 819467d76b..154864c15d 100644 --- a/reconcile/test/utils/test_quay_api.py +++ b/reconcile/test/utils/test_quay_api.py @@ -94,3 +94,173 @@ def test_list_team_members_raises_other_status_codes( with pytest.raises(HTTPError): quay_api.list_team_members(TEAM_NAME) + + +def test_list_robot_accounts(quay_api: QuayApi, httpserver: HTTPServer) -> None: + httpserver.expect_request( + f"/api/v1/organization/{ORG}/robots", + method="GET", + ).respond_with_json( + { + "robots": [ + { + "name": "robot1", + "description": "robot1 description", + "created": "2021-01-01T00:00:00Z", + "last_accessed": None, + }, + { + "name": "robot2", + "description": "robot2 description", + "created": "2021-01-01T00:00:00Z", + "last_accessed": None, + }, + ] + }, + status=200, + ) + + assert quay_api.list_robot_accounts() == [ + { + "name": "robot1", + "description": "robot1 description", + "teams": [], + "repositories": [], + }, + { + "name": "robot2", + "description": "robot2 description", + "teams": [], + "repositories": [], + }, + ] + + +def test_list_robot_accounts_raises_other_status_codes( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/organization/{ORG}/robots", + method="GET", + ).respond_with_json({"error": "Bad request"}, status=400) + + with pytest.raises(HTTPError): + quay_api.list_robot_accounts() + + +def test_create_robot_account(quay_api: QuayApi, httpserver: HTTPServer) -> None: + httpserver.expect_request( + f"/api/v1/organization/{ORG}/robots/robot1", + method="PUT", + ).respond_with_json( + {"name": "robot1", "description": "robot1 description"}, status=200 + ) + + quay_api.create_robot_account("robot1", "robot1 description") + + assert len(httpserver.log) == 1 + request = httpserver.log[0][0] + assert request.method == "PUT" + assert json.loads(request.get_data()) == {"description": "robot1 description"} + + +def test_delete_robot_account(quay_api: QuayApi, httpserver: HTTPServer) -> None: + httpserver.expect_request( + f"/api/v1/organization/{ORG}/robots/robot1", + method="DELETE", + ).respond_with_json({}, status=200) + + quay_api.delete_robot_account("robot1") + + assert len(httpserver.log) == 1 + request = httpserver.log[0][0] + assert request.method == "DELETE" + + +def test_delete_robot_account_raises_other_status_codes( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/organization/{ORG}/robots/robot1", + method="DELETE", + ).respond_with_json({"error": "Bad request"}, status=400) + + with pytest.raises(HTTPError): + quay_api.delete_robot_account("robot1") + + +def test_get_repo_robot_account_permissions( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="GET", + ).respond_with_json({"role": "write"}, status=200) + + result = quay_api.get_repo_robot_account_permissions("some-repo", "robot1") + assert result == "write" + + +def test_get_repo_robot_permissions_raises_other_status_codes( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="GET", + ).respond_with_json({"error": "Bad request"}, status=400) + + with pytest.raises(HTTPError): + quay_api.get_repo_robot_account_permissions("some-repo", "robot1") + + +def test_set_repo_robot_permissions(quay_api: QuayApi, httpserver: HTTPServer) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="PUT", + ).respond_with_json({}, status=200) + + quay_api.set_repo_robot_account_permissions("some-repo", "robot1", "admin") + + assert len(httpserver.log) == 1 + request = httpserver.log[0][0] + assert request.method == "PUT" + assert json.loads(request.get_data()) == {"role": "admin"} + + +def test_set_repo_robot_permissions_raises_other_status_codes( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="PUT", + ).respond_with_json({"error": "Bad request"}, status=400) + + with pytest.raises(HTTPError): + quay_api.set_repo_robot_account_permissions("some-repo", "robot1", "admin") + + +def test_delete_repo_robot_permissions( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="DELETE", + ).respond_with_json({}, status=200) + + quay_api.delete_repo_robot_account_permissions("some-repo", "robot1") + + assert len(httpserver.log) == 1 + request = httpserver.log[0][0] + assert request.method == "DELETE" + + +def test_delete_repo_robot_permissions_raises_other_status_codes( + quay_api: QuayApi, httpserver: HTTPServer +) -> None: + httpserver.expect_request( + f"/api/v1/repository/{ORG}/some-repo/permissions/user/{ORG}+robot1", + method="DELETE", + ).respond_with_json({"error": "Bad request"}, status=400) + + with pytest.raises(HTTPError): + quay_api.delete_repo_robot_account_permissions("some-repo", "robot1") diff --git a/reconcile/utils/quay_api.py b/reconcile/utils/quay_api.py index f929a71fbe..8f943313e9 100644 --- a/reconcile/utils/quay_api.py +++ b/reconcile/utils/quay_api.py @@ -1,5 +1,5 @@ import contextlib -from typing import Any +from typing import Any, TypedDict import requests @@ -10,6 +10,13 @@ class QuayTeamNotFoundError(Exception): pass +class RobotAccountDetails(TypedDict): + name: str + description: str | None + teams: list[dict[str, str]] + repositories: list[dict[str, str]] + + class QuayApi(ApiBase): LIMIT_FOLLOWS = 15 @@ -240,3 +247,61 @@ def set_repo_team_permissions(self, repo_name: str, team: str, role: str) -> Non ) body = {"role": role} self._put(url, data=body) + + def list_robot_accounts(self) -> list[RobotAccountDetails]: + url = f"/api/v1/organization/{self.organization}/robots" + body = self._get(url) + return [ + RobotAccountDetails( + name=robot["name"], + description=robot["description"], + teams=[], + repositories=[], + ) + for robot in body["robots"] + ] + + def create_robot_account(self, name: str, description: str) -> None: + url = f"/api/v1/organization/{self.organization}/robots/{name}" + body = {"description": description} + self._put(url, data=body) + + def delete_robot_account(self, name: str) -> None: + url = f"/api/v1/organization/{self.organization}/robots/{name}" + self._delete(url) + + def get_robot_account_permissions(self, name: str) -> list[dict[str, Any]]: + url = f"/api/v1/organization/{self.organization}/robots/{name}/permissions" + body = self._get(url) + return body["permissions"] + + def set_robot_account_permissions( + self, name: str, permissions: list[dict[str, Any]] + ) -> None: + url = f"/api/v1/organization/{self.organization}/robots/{name}/permissions" + body = {"permissions": permissions} + self._put(url, data=body) + + def delete_robot_account_permissions(self, name: str) -> None: + url = f"/api/v1/organization/{self.organization}/robots/{name}/permissions" + self._delete(url) + + def get_repo_robot_account_permissions( + self, repo_name: str, robot_name: str + ) -> str | None: + url = f"/api/v1/repository/{self.organization}/{repo_name}/permissions/user/{self.organization}+{robot_name}" + body = self._get(url) + return body.get("role") or None + + def set_repo_robot_account_permissions( + self, repo_name: str, robot_name: str, role: str + ) -> None: + url = f"/api/v1/repository/{self.organization}/{repo_name}/permissions/user/{self.organization}+{robot_name}" + body = {"role": role} + self._put(url, data=body) + + def delete_repo_robot_account_permissions( + self, repo_name: str, robot_name: str + ) -> None: + url = f"/api/v1/repository/{self.organization}/{repo_name}/permissions/user/{self.organization}+{robot_name}" + self._delete(url)