🥒 CCC.ObjStor Test: ccc-test-bucket-20260526t102300z

Test Parameters

ServiceTypeobject-storage
ProviderServiceTypestorage.googleapis.com/Bucket
CatalogTypesCCC.ObjStor
TagFilter@object-storage, @PerService, ~@NEGATIVE, ~@OPT_IN
UIDprojects/nodal-time-474015-p5/buckets/ccc-test-bucket-20260526t102300z
ResourceNameccc-test-bucket-20260526t102300z
ReportFileccc-test-bucket-20260526t102300z-service
ReportTitleccc-test-bucket-20260526t102300z
Instance
{
  "ID": "main-gcp",
  "Properties": {
    "Provider": "gcp",
    "Region": "us-central1",
    "AzureResourceGroup": "",
    "AzureSubscriptionID": "",
    "GcpProjectId": "nodal-time-474015-p5"
  },
  "Services": [
    {
      "Type": "object-storage",
      "Properties": {
        "gcp-bucket-name": "ccc-test-bucket-20260526t102300z",
        "object-storage-retention-period-seconds": 172800
      }
    },
    {
      "Type": "logging",
      "Properties": {
        "gcp-log-bucket-name": "cfi-test-log-bucket"
      }
    }
  ],
  "Rules": {
    "permitted-project-ids": "",
    "permitted-regions": [
      "us-central1"
    ]
  }
}
GcpBucketNameccc-test-bucket-20260526t102300z
GcpLogBucketNamecfi-test-log-bucket
GcpProjectIdnodal-time-474015-p5
ObjectStorageRetentionPeriodSeconds172800
PermittedRegions
[
  "us-central1"
]
Providergcp
Regionus-central1

Summary

Generated: 2026-05-26 10:24:45

Total Run Time: 1m2s

Features: 41

Scenarios: 82 (✅ 30 | ❌ 52)

Steps: 669 (✅ 472 | ❌ 52 | ⏭️ 139 | ❓ 6)

Feature: CCC.Core.CN01.AR01
Scenario: Storage account enforces minimum TLS version @CCC.Core @tlp-green @tlp-amber @tlp-red @CCC.Core.CN01 @Policy @PerService @object-storage
Given a cloud api for "{Instance}" in "api"45µs
When I attempt policy check "object-storage-tls-policy" for control "CCC.Core.CN01" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"2s
policy check failed: GCP Cloud Storage HTTPS Policy Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true25µs
📎 Attachments:
policy-result-object-storage-tls-policy.json
View JSON (1388 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN01/AR01/object-storage-tls-policy/gcp.yaml",
  "name": "GCP Cloud Storage HTTPS Policy Check",
  "service_type": "object-storage",
  "requirement_text": "When a port is exposed for non-SSH network traffic, all traffic MUST include  a TLS handshake AND be encrypted using TLS 1.3 or higher.\n",
  "validity_score": 8,
  "validity_commentary": "This check verifies that GCP Cloud Storage is accessed over HTTPS. Strengths: - GCS API explicitly requires TLS for all operations on the public endpoint - Google manages the TLS termination and certificate lifecycle - Organization-level policy 'constraints/storage.requireHttpsTrafficOnly'\n  can be used for universal enforcement\nLimitations: - GCP does not expose a per-bucket 'minimum TLS version' field - TLS 1.3 is supported but cannot be set as the exclusive minimum yet\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN01.AR03
Scenario: Object storage policy prevents the use of unencrypted ports @tlp-green @tlp-amber @tlp-red @CCC.Core @CCC.Core.CN01 @Policy @PerService @object-storage
When I attempt policy check "object-storage-unencrypted-policy" for control "CCC.Core.CN01" assessment requirement "AR03" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"885ms
policy check failed: GCP Cloud Storage Unencrypted Traffic Block Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true26µs
📎 Attachments:
policy-result-object-storage-unencrypted-policy.json
View JSON (1330 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN01/AR03/object-storage-unencrypted-policy/gcp.yaml",
  "name": "GCP Cloud Storage Unencrypted Traffic Block Check",
  "service_type": "object-storage",
  "requirement_text": "Unencrypted traffic MUST be blocked or redirected to secure equivalents so that no data is transmitted in plaintext.\n",
  "validity_score": 8,
  "validity_commentary": "This check verifies that GCP Cloud Storage is accessed over HTTPS. Strengths: - GCS API implicitly requires TLS for all operations on the public endpoint - Google manages the TLS termination; plaintext is not accepted Limitations: - GCP does not expose a per-bucket HTTPS-only flag; enforcement is platform-level - Organization policy 'constraints/storage.requireHttpsTrafficOnly' can provide\n  additional enforcement\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN01.AR08
Scenario: Storage account enforces mutual TLS @tls @tlp-amber @tlp-red @CCC.Core @CCC.Core.CN01 @Policy @NotTested @PerService @object-storage
Then no-op required23µs
Feature: CCC.Core.CN02.AR01 - Data Encryption at Rest
Scenario: Verify objects are encrypted at rest @PerService @CCC.Core @CCC.Core.CN02 @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"36µs
Given I call "{api}" with "GetServiceAPI" using argument "object-storage"85µs
And I refer to "{result}" as "storage"22µs
And "{result}" is not an error25µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-encryption-check={Timestamp}.txt", and "encryption test data"150ms
Then "{result}" is not an error27µs
And I refer to "{result}" as "uploadResult"26µs
And "{uploadResult.Encryption}" is not null19µs
And "{uploadResult.EncryptionAlgorithm}" is "AES256"30µs
And I attach "{uploadResult}" to the test output as "Upload Result with Encryption Details"63µs
📎 Attachments:
Upload Result with Encryption Details
View JSON (269 bytes)
{"ID":"test-encryption-check=1779791088569.txt","BucketID":"ccc-test-bucket-20260526t102300z","Name":"test-encryption-check=1779791088569.txt","Size":20,"Data":["encryption test data"],"Encryption":"Google","EncryptionAlgorithm":"AES256","VersionID":"1779791088652117"}
Scenario: Object storage encryption compliance @PerService @CCC.Core @CCC.Core.CN02 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"74µs
When I attempt policy check "object-storage-encryption" for control "CCC.Core.CN02" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"880ms
policy check failed: GCP Cloud Storage Bucket Encryption Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true23µs
📎 Attachments:
policy-result-object-storage-encryption.json
View JSON (1250 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN02/AR01/object-storage-encryption/gcp.yaml",
  "name": "GCP Cloud Storage Bucket Encryption Check",
  "service_type": "object-storage",
  "requirement_text": "When data is stored, it MUST be encrypted using the latest industry-standard  encryption methods.\n",
  "validity_score": 9,
  "validity_commentary": "This query validates GCP Cloud Storage bucket encryption configuration. GCP encrypts all data at rest by default using AES-256. Strengths: - All GCS data is encrypted by default - Supports Google-managed, CMEK, and CSEK keys - Validates CMEK configuration when specified Limitations: - Does not validate KMS key configuration details - Does not verify key rotation policies\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN03.AR01 - Multi-Factor Authentication for Destructive Operations
Scenario: Object storage delete protection compliance @PerService @CCC.Core @CCC.Core.CN03 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"46µs
When I attempt policy check "object-storage-delete-protection" for control "CCC.Core.CN03" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"882ms
policy check failed: GCP Cloud Storage Soft Delete and Versioning Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true32µs
📎 Attachments:
policy-result-object-storage-delete-protection.json
View JSON (1459 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN03/AR01/object-storage-delete-protection/gcp.yaml",
  "name": "GCP Cloud Storage Soft Delete and Versioning Configuration",
  "service_type": "object-storage",
  "requirement_text": "When an entity attempts to modify the service through a user interface, the  authentication process MUST require multiple identifying factors for authentication.\n",
  "validity_score": 5,
  "validity_commentary": "GCP does not have a direct equivalent to S3 MFA Delete at the storage level. MFA in GCP is enforced at the IAM/Identity Platform level. This check validates soft delete and versioning as compensating controls. Strengths: - Soft delete allows recovery of deleted objects - Object versioning preserves all object versions - GCP Identity Platform supports MFA for all operations Limitations: - This is NOT a direct MFA-for-delete check - MFA enforcement is at the identity layer, not storage layer\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: MFA requirement for destructive operations cannot be tested automatically @PerService @CCC.Core @CCC.Core.CN03 @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage @load-balancer
Given a cloud api for "{Instance}" in "api"52µs
Then no-op required30µs
Feature: CCC.Core.CN03.AR02 - API Authentication with Credentials
Scenario: API modification requires credential and trust perimeter origin @PerService @CCC.Core @CCC.Core.CN03 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @NotTestable @object-storage @load-balancer
Given a cloud api for "{Instance}" in "api"37µs
Then no-op required22µs
Feature: CCC.Core.CN03.AR03 - MFA for UI Viewing
Scenario: UI viewing requires multi-factor authentication @PerService @CCC.Core @CCC.Core.CN03 @tlp-amber @tlp-red @Policy @NotTestable @object-storage @load-balancer
Given a cloud api for "{Instance}" in "api"34µs
Then no-op required29µs
Feature: CCC.Core.CN03.AR04 - API Authentication for Viewing
Scenario: API viewing requires credential and trust perimeter origin @PerService @CCC.Core @CCC.Core.CN03 @tlp-amber @tlp-red @Policy @NotTestable @object-storage @load-balancer
Given a cloud api for "{Instance}" in "api"33µs
Then no-op required27µs
Feature: CCC.Core.CN04.AR01 - Log Administrative Access Attempts
Scenario: Object storage admin logging compliance @PerService @CCC.Core @CCC.Core.CN04 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @object-storage
When I attempt policy check "admin-logging" for control "CCC.Core.CN04" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"857ms
policy check failed: Cloud Audit Logs Admin Activity Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true27µs
📎 Attachments:
policy-result-admin-logging.json
View JSON (1321 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN04/AR01/admin-logging/gcp.yaml",
  "name": "Cloud Audit Logs Admin Activity Configuration",
  "service_type": "all",
  "requirement_text": "The service MUST log all access and changes by administrators  (identity, timestamp, action, result).\n",
  "validity_score": 9,
  "validity_commentary": "This query validates that Cloud Audit Logs Admin Activity logging is enabled. Admin Activity logs are always enabled by default in GCP and cannot be disabled. Strengths: - Admin Activity logs are enabled by default and cannot be disabled - Logs include principal, timestamp, method, and status - Stored in Cloud Logging separate from the bucket Limitations: - Does not validate log retention period - Does not verify log sink configuration for long-term storage\n",
  "query_template": "gcloud logging sinks list \\\n  --project=${GcpProjectId} \\\n  --format=json\n",
  "query_executed": "gcloud logging sinks list \\\n  --project=nodal-time-474015-p5 \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Verify admin actions are logged with identity and timestamp @PerService @CCC.Core @CCC.Core.CN04 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"43µs
And I call "{api}" with "GetServiceAPI" using argument "{ServiceType}"43µs
And I refer to "{result}" as "theService"23µs
Given I call "{api}" with "GetServiceAPI" using argument "logging"401µs
And I refer to "{result}" as "loggingService"31µs
When I call "{theService}" with "UpdateResourcePolicy"263ms
Then "{result}" is not an error23µs
And I attach "{result}" to the test output as "Policy Update Result"35µs
And we wait for a period of "10000" ms10s
When I call "{loggingService}" with "QueryAdminLogs" using arguments "{ResourceName}" and "{20}"78µs
Then "{result}" is not an error17µs
And I refer to "{result}" as "adminLogs"13µs
And I attach "{adminLogs}" to the test output as "Admin Activity Logs"51µs
Then "{adminLogs}" is an array of objects with at least the following contents77µs
result
Succeeded
expected row not found: map[result:Succeeded]
📎 Attachments:
Policy Update Result
View JSON (4 bytes)
null
Admin Activity Logs
View JSON (2 bytes)
[]
Feature: CCC.Core.CN04.AR02 - Log Data Modification Attempts
Scenario: Object storage data modification logging compliance @PerService @CCC.Core @CCC.Core.CN04 @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"39µs
When I attempt policy check "data-write-logging" for control "CCC.Core.CN04" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"894ms
policy check failed: Cloud Audit Logs Data Write Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true22µs
📎 Attachments:
policy-result-data-write-logging.json
View JSON (1311 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN04/AR02/data-write-logging/gcp.yaml",
  "name": "Cloud Audit Logs Data Write Configuration",
  "service_type": "all",
  "requirement_text": "The service MUST log all data modification attempts  (identity, timestamp, action, result).\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that Data Write audit logs are enabled. Data Write logs capture resource creation, deletion, and modification. Strengths: - Captures object-level write operations - Logs include principal, timestamp, method, and status - Stored in Cloud Logging separate from the bucket Limitations: - Data Write logs must be explicitly enabled (not default) - High-volume buckets may incur significant logging costs - Requires IAM configuration at project or organization level\n",
  "query_template": "gcloud projects get-iam-policy ${GcpProjectId} \\\n  --format=json\n",
  "query_executed": "gcloud projects get-iam-policy nodal-time-474015-p5 \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN04.AR03 - Log Data Read Attempts
Scenario: Data read logging compliance @PerService @CCC.Core @CCC.Core.CN04 @tlp-red @Policy @object-storage @vpc
Given a cloud api for "{Instance}" in "api"36µs
When I attempt policy check "data-read-logging" for control "CCC.Core.CN04" assessment requirement "AR03" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"882ms
policy check failed: Cloud Audit Logs Data Read Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true27µs
📎 Attachments:
policy-result-data-read-logging.json
View JSON (1303 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN04/AR03/data-read-logging/gcp.yaml",
  "name": "Cloud Audit Logs Data Read Configuration",
  "service_type": "all",
  "requirement_text": "The service MUST log all data read attempts  (identity, timestamp, action, result).\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that Data Read audit logs are enabled. Data Read logs capture resource download and metadata read operations. Strengths: - Captures object-level read operations - Logs include principal, timestamp, method, and status - Stored in Cloud Logging separate from the bucket Limitations: - Data Read logs must be explicitly enabled (not default) - High-volume buckets may incur very significant logging costs - Requires IAM configuration at project or organization level\n",
  "query_template": "gcloud projects get-iam-policy ${GcpProjectId} \\\n  --format=json\n",
  "query_executed": "gcloud projects get-iam-policy nodal-time-474015-p5 \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Verify data read operations are logged with identity and timestamp @PerService @CCC.Core @CCC.Core.CN04 @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"41µs
Given I call "{api}" with "GetServiceAPI" using argument "object-storage"39µs
And I refer to "{result}" as "storage"19µs
Given I call "{api}" with "GetServiceAPI" using argument "logging"17µs
And I refer to "{result}" as "loggingService"12µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-read-logging-object={Timestamp}.txt", and "test data for read logging verification"133ms
Then "{result}" is not an error23µs
And I refer to "{result}" as "createResult"15µs
When I call "{storage}" with "ReadObject" using arguments "{ResourceName}" and "test-read-logging-object={Timestamp}.txt"102ms
Then "{result}" is not an error21µs
And I refer to "{result}" as "readResult"19µs
And I attach "{readResult}" to the test output as "Object Read Result"41µs
And we wait for a period of "10000" ms10s
When I call "{loggingService}" with "QueryDataReadLogs" using arguments "{ResourceName}" and "{20}"42µs
Then "{result}" is not an error51µs
And I refer to "{result}" as "readLogs"20µs
And I attach "{readLogs}" to the test output as "Data Read Logs"36µs
Then "{readLogs}" is an array of objects with at least the following contents35µs
result
Succeeded
expected row not found: map[result:Succeeded]
📎 Attachments:
Object Read Result
View JSON (266 bytes)
{"ID":"test-read-logging-object=1779791103396.txt","BucketID":"ccc-test-bucket-20260526t102300z","Name":"test-read-logging-object=1779791103396.txt","Size":39,"Data":["test data for read logging verification"],"Encryption":"","EncryptionAlgorithm":"","VersionID":""}
Data Read Logs
View JSON (2 bytes)
[]
Feature: CCC.Core.CN05.AR01 - Block Unauthorized Data Modification
Scenario: Service prevents data modification by user with no access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Destructive @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"36µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"41µs
And I refer to "{result}" as "storage"29µs
And I call "{api}" with "GetServiceAPI" using argument "iam"24µs
And I refer to "{result}" as "iamService"16µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-write-access", "{UID}", and "none"1s
And I refer to "{result}" as "testUserNoAccess"52µs
And I attach "{result}" to the test output as "no-access-user-identity.json"80µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"269µs
And "{result}" is not an error30µs
And I refer to "{result}" as "userStorage"32µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "test-cn05-unauthorized-modify={Timestamp}.txt", and "unauthorized data"219ms
Then "{result}" is an error23µs
And I attach "{result}" to the test output as "no-access-create-error.txt"29µs
📎 Attachments:
no-access-user-identity.json
View JSON (3067 bytes)
{"UserName":"test-user-no-write-access","Provider":"gcp","Credentials":{"client_email":"test-user-no-write-access@nodal-time-474015-p5.iam.gserviceaccount.com","email":"test-user-no-write-access@nodal-time-474015-p5.iam.gserviceaccount.com","private_key_id":"79cbc3f1d6f12e66a4f1c85644538b525d7adadc","project_id":"nodal-time-474015-p5","service_account_key":"{\n  \"type\": \"service_account\",\n  \"project_id\": \"nodal-time-474015-p5\",\n  \"private_key_id\": \"79cbc3f1d6f12e66a4f1c85644538b525d7adadc\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuXDAU0XQWREE9\\nJfm/xCeuZVXhXlxOL5hgxVv9Y+8Y1rdI34Z8vQH857W2rpC12AuxaXaqabnEMRU8\\nZDj0s7MqZgpRdya0/x/3P3ekEuBPy1nAqwwADh2E7oQiVHJW5ZGXCPSOhQCLRSLb\\nLjuVokRiGIJYRzxW5m9Mp0KVMF0R5SAkpJFP2us1ArjvAtbfMWQlCX2h0N3+lgX5\\nMRvIgcD4fcDeO+UemzCIHUSQIYd7GHbC5Q7jxzwFicPevJePmONW1ZMmtOy+u+nx\\n3Ul0n3xgRzHnSXs325pPDKaxsk6uz0RbDLINpeFdwj8MfVaQtBY2iGCDVN5Ut0SK\\ncmskiXv1AgMBAAECggEAGBS3YfNY+xz2KFcvBSM278kjG/syTcIZDinJKK09VSA3\\n3s1a/64DBkY3kewjea9FqNJjXJSO3t/V36oKi7v932SJwZ1D2p+ZxJt0D1RkEovd\\nRiou1XBy90G8khk4/si6BjLAbqaZNU2ZIM25K6i7lRNu0nkUMP77xDRy57Pu8WI0\\nuQPpvpwRBSW06uuyFmmA/W4vCtbnOiXK1DS9cU6w+58jQIJFGca+NY4sQz3XWzCN\\nUl7JizCB5mzQu0uT4KvWKSvew1KCtEdy1ho90jZbu2mHryLIKSzyfHqQFTvhjgdn\\nfh8L30y/V9A0all7KsSC/kSl9LmyhdCJero3FVEKCQKBgQDW0xwlOEUXIGS1xSat\\nWyNtP/OKxrBSiltfAD8ptJQjbbBhPXdcWlS+3wVzzLi9XLQ/rITP1BHLAEIt7ju7\\nYCpq9yCZNAxXYPPg7KyQeJdU8jOe3PX+/dsxQmSu438pVwFOWAtcAEiF7wYGbUj7\\nBVRUfTr0zH9OAXEG6lKQfPhEWwKBgQDPx5ZpCqfiMBGrbiy4weSc0KHS2SYa7tEq\\nkH+PSwBGKEd+he5d2bfcF0X1t7dOMMwExh/NCxZ1ofd+LbMFIdhIOfBMH6/cZCZz\\nUipVMFTqfuqW4wl/ZT5Sfui9Q+ChkKU1h7trocIVXmtTMT4emMBqlvoSz0ytBKev\\nxzOVDbjx7wKBgB5QbAhUiGtbBtsflvWfhsBD5foPT5JWM86UGlWoRb86G0mdgtpl\\nZNAKaJqOqQMPsd/KWHN7WYdr4erZU1R9nX66oL79uUAbTk7PFwrL+Y7jHqWsSIpT\\nCDtLQynqsGcFAAouImw5HgLIV/FQOpwxhFTn1wn0UYKQcYKoTj5VZDNBAoGBAJGZ\\n9k/TlMPPFYLBKPure61cEhoz6xzyf4bJTWo3j5CaR0dlSR1hJRNJB9BhlkVnsoAh\\n6kUAYRO7lThJg+qzxeEPINHnXpAdakhjqqCZxtewammj3ZL1eo/KuQNwHmh5eRwi\\n6nZJGz1oNeNNXY+JUUUgWUt3Eu8nlO57tCzeOdznAoGAb9d07Nh/Fbn79WSYHL7o\\nqCThGvZAa4zRE6tdn/cU3avf52sPEsi4YeKYHv2RlvjewSCht3VDAs6VJkH1/M6j\\nhORylh4xqpkrQz4gCEVzO+DRdPurkCT18YD3XlG7Qg4GHzUHXPqXfltUMISEJBg6\\nIQDp+5Z/JIitgN7y6bNLzwI=\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"test-user-no-write-access@nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"client_id\": \"118325143407635661704\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/test-user-no-write-access%40nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n","unique_id":"118325143407635661704"},"Policy":"{\"user\": \"test-user-no-write-access\", \"service\": \"projects/nodal-time-474015-p5/buckets/ccc-test-bucket-20260526t102300z\", \"level\": \"none\", \"role\": \"\"}"}
no-access-create-error.txt
View Content (344 bytes)
failed to close writer for object test-cn05-unauthorized-modify=1779791113641.txt: googleapi: Error 403: test-user-no-write-access@nodal-time-474015-p5.iam.gserviceaccount.com does not have storage.objects.create access to the Google Cloud Storage object. Permission 'storage.objects.create' denied on resource (or it may not exist)., forbidden
Scenario: Service allows data modification by user with write access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Destructive @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"66µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"78µs
And I refer to "{result}" as "storage"39µs
And I call "{api}" with "GetServiceAPI" using argument "iam"43µs
And I refer to "{result}" as "iamService"22µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write-access", "{UID}", and "write"1s
And I refer to "{result}" as "testUserWrite"33µs
And I attach "{result}" to the test output as "write-user-identity.json"93µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"83ms
And "{result}" is not an error33µs
expected {result} to not be an error, but got: credentials not ready: credentials not ready for GCS access: Get "https://storage.googleapis.com/storage/v1/b?alt=json&pageToken=&prefix=&prettyPrint=false&project=nodal-time-474015-p5&projection=full&returnPartialSuccess=false": auth: cannot fetch token: 400 Response: {"error":"invalid_grant","error_description":"Invalid grant: account not found"}
And I refer to "{result}" as "userStorage"24µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "test-cn05-authorized-modify={Timestamp}.txt", and "authorized data"22µs
Then "{result}" is not an error20µs
And I attach "{result}" to the test output as "write-create-object-result.json"18µs
📎 Attachments:
write-user-identity.json
View JSON (3062 bytes)
{"UserName":"test-user-write-access","Provider":"gcp","Credentials":{"client_email":"test-user-write-access@nodal-time-474015-p5.iam.gserviceaccount.com","email":"test-user-write-access@nodal-time-474015-p5.iam.gserviceaccount.com","private_key_id":"6fd238869e6a63bdb0a0dd0674e8a1e467b8e88d","project_id":"nodal-time-474015-p5","service_account_key":"{\n  \"type\": \"service_account\",\n  \"project_id\": \"nodal-time-474015-p5\",\n  \"private_key_id\": \"6fd238869e6a63bdb0a0dd0674e8a1e467b8e88d\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+D4U67PMPd/2w\\nq6arIf1c7IL7eVBgL8aKGDV+sDdEVt/u84El4OmhYhlpnFU60UbbdMNMqZ8VBkto\\nMaFbVP5w/72HuvPz3ikgmKNdLfA6d00u5cyn6BUz7jY8C9w55vmvXTMh/IvDBqyn\\nB9J/raMY4HVYMmDgnLO8T8cbpLZX9upJ2b5HupgkwRJfMLVK7BugbG1Vy6OYurjx\\nbLUT/cGmDCUiPJH+EwroHnuzapx1IaJFV5AlO68T1y0lMnHg0JX0m3q26KCxm3gU\\ncK4BNgOKF6BYI8EdP5DHHEiwQm98FihUzzfft6mDblaOiolBZ+ehXimwe2cORTic\\npuYaLEkjAgMBAAECggEAA55fUPEcar965LCVrf+8LCBA9L8yfFpX8QNL/E2V4zkj\\nXH4ch+Bz4kzLozZXIxVVrhtFOqamrtACOa4h8LQnyOP9oSre23rdlOGnrFJtX/wr\\nXfZvHgVJZzPJPP2UiFaMsAb+dSn724YWprvEwCpJ0CyDBAQViWXUrfGunrswmnCL\\nrJqTFlktDOKKQS10V83EUx5N2CLE0ezz/HN6sRYE64BVg/SzxoJ3FusBnJOJuABz\\nJecVw5X8ADt5xCfdcnp5YcQjwqGLQmXprlazgcxdwvU1WbQWPl5VwZZUl77QXE+G\\n9tKi2MyFswbThMG6K+eB79NQQnwhZ9U1WqxLVApCfQKBgQD5RY+sH2R5ecQ3OYg/\\nagRlm6J/WqtEjWtoSN/3wujUQHh7Stw8LocF2XsWxsEPGnyr9pPgIKz/mi7MIBVj\\nPcCEf/Wc+tOavysEqk+eFpC5TG8VOf2AL4yT7nItOPPaLBJI7H4LU7WJGgTmVgRx\\nOLFM2/1BUFXqI8qkOKoA11YdjwKBgQDDMNE/w30QIf5HOTzRl5wj+wRhKcrmg8XM\\n546DQbl3mXXaSdAWUCoT7RqLTWj/Pa6HtfywVZ6GGuCFUlSipomReOhvrqeezkBP\\nIxBufz1ChlJbAqfegNCFMYMEGxcq2eSwqTdRYxckPcAy1KHOQDPcMZwJMvlxujZ0\\n0doL+6f5LQKBgF7i9szLamC/VEy9Trrs7V2MP/AAoJ9IwfEBhJf4js50+CfemDUk\\ndOtqHOvPnp/UMk73XtT7Oz9U/qlfMSUE1araVrF53WDTklmFRydjaZXPnZ1T5MaN\\n0xJguv+x5UlQa2ls9JH1PG5DBEh1x90deohKWX4qSXoGQ9X9Z+FIFxTLAoGBAME7\\n4uutLHJ8NK9uCrezz/AO4RcPuL7cVUW1N3DZ8DJmyjWAPXDZi86OPGkMCZYmClJv\\n5+jp2jYJBZz3FLKxDB/oArQNxAODTEcL/4hkjtD9CSrwRiAQhl5V1c6KwzS44Z3C\\n5/C6mH5YY53uwwDcrnqe4kp5HFlqb97WoXabfH9BAoGANLmsy8dQn9yTJjvA4Lz/\\nVYV0x4FakH+HQpIdNF5A7/1AtGBq2CsG7Bb0VprNn0qJaJJ329Igl+QcUOSGUJtQ\\nI3V1jf4Li799m5YwMamVS7Vs/lGfkwLt7AHtwklz15paH9JcHW+3KyG+Y2En7BLo\\nbrfJGxToqWkFumsP+gPB968=\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"test-user-write-access@nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"client_id\": \"107332673065103117761\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/test-user-write-access%40nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n","unique_id":"107332673065103117761"},"Policy":"{\"user\": \"test-user-write-access\", \"service\": \"projects/nodal-time-474015-p5/buckets/ccc-test-bucket-20260526t102300z\", \"level\": \"write\", \"role\": \"roles/editor\"}"}
Scenario: Storage is not configured for public write access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"47µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"38µs
And I refer to "{result}" as "storage"25µs
And I call "{api}" with "GetServiceAPI" using argument "iam"31µs
And I refer to "{result}" as "iamService"25µs
When I attempt policy check "object-storage-block-public-write-access" for control "CCC.Core.CN05" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"890ms
policy check failed: GCP Cloud Storage Public Access Prevention: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true29µs
📎 Attachments:
policy-result-object-storage-block-public-write-access.json
View JSON (1717 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN05/AR01/object-storage-block-public-write-access/gcp.yaml",
  "name": "GCP Cloud Storage Public Access Prevention",
  "service_type": "object-storage",
  "requirement_text": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities. Public access prevention ensures the bucket is not world-writable.\n",
  "validity_score": 8,
  "validity_commentary": "This query validates that GCP Cloud Storage has public access prevention enabled. When set to 'enforced', the bucket cannot be made public via IAM or ACLs, reducing the risk of unauthorized data modification. Strengths: - Prevents allUsers and allAuthenticatedUsers access when enforced - Cannot be overridden by IAM policy or ACL changes - Aligns with Google security best practices Limitations: - Does not validate IAM policies for principle of least privilege - Behavioral testing (CN05-AR01) verifies unauthorized modification is blocked at runtime - 'inherited' uses org-level policy; org policy should restrict public access\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(iamConfiguration.publicAccessPrevention)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(iamConfiguration.publicAccessPrevention)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN05.AR02 - Block Unauthorized Administrative Access
Scenario: Service prevents administrative action (creating a new bucket) by user with no access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Destructive @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"46µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"44µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"29µs
And I refer to "{result}" as "iamService"24µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-admin-access", "{UID}", and "none"1s
And I refer to "{result}" as "testUserNoAccess"31µs
And I attach "{result}" to the test output as "no-admin-user-identity.json"57µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"45µs
And "{result}" is not an error35µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"25µs
When I call "{userStorage}" with "CreateBucket" using argument "test-cn05-unauthorized-admin-container"33µs
Then "{result}" is an error26µs
And I attach "{result}" to the test output as "no-admin-create-bucket-error.txt"27µs
📎 Attachments:
no-admin-user-identity.json
View Content (250 bytes)
failed to create service account key for test-user-no-admin-access: rpc error: code = NotFound desc = Service account projects/nodal-time-474015-p5/serviceAccounts/test-user-no-admin-access@nodal-time-474015-p5.iam.gserviceaccount.com does not exist.
Scenario: Service prevents administrative action (creating a new bucket) by user with read-only access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Destructive @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"98µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"57µs
And I refer to "{result}" as "storage"24µs
And I call "{api}" with "GetServiceAPI" using argument "iam"24µs
And I refer to "{result}" as "iamService"15µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read-only-admin", "{UID}", and "read"1s
And I refer to "{result}" as "testUserRead"23µs
And I attach "{result}" to the test output as "read-only-admin-user-identity.json"39µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{false}"41µs
And "{result}" is not an error38µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"16µs
When I call "{userStorage}" with "CreateBucket" using argument "test-cn05-read-only-create-container"20µs
Then "{result}" is an error17µs
And I attach "{result}" to the test output as "read-only-create-bucket-error.txt"19µs
📎 Attachments:
read-only-admin-user-identity.json
View Content (250 bytes)
failed to create service account key for test-user-read-only-admin: rpc error: code = NotFound desc = Service account projects/nodal-time-474015-p5/serviceAccounts/test-user-read-only-admin@nodal-time-474015-p5.iam.gserviceaccount.com does not exist.
Scenario: Service allows administrative action (creating a new bucket) by user with admin access @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"34µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"38µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"21µs
And I refer to "{result}" as "iamService"16µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-admin-access", "{UID}", and "admin"130ms
And I refer to "{result}" as "testUserAdmin"25µs
And I attach "{result}" to the test output as "admin-user-identity.json"31µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserAdmin}", and "{true}"53µs
And "{result}" is not an error38µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"22µs
When I call "{userStorage}" with "CreateBucket" using argument "test-cn05-authorized-admin-container"31µs
Then "{result}" is not an error24µs
And I attach "{result}" to the test output as "admin-create-bucket-result.json"33µs
And I call "{storage}" with "DeleteBucket" using argument "test-cn05-authorized-admin-container"15µs
📎 Attachments:
admin-user-identity.json
View Content (235 bytes)
failed to create service account test-user-admin-access: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Unauthorized administrative access is blocked @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"40µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"40µs
And I refer to "{result}" as "storage"25µs
And I call "{api}" with "GetServiceAPI" using argument "iam"34µs
And I refer to "{result}" as "iamService"28µs
Then no-op required22µs
Feature: CCC.Core.CN05.AR03 - Block Cross-Tenant Access
Scenario: Cross-tenant access is blocked without explicit allowlist @PerService @CCC.Core @CCC.Core.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"28µs
When I attempt policy check "object-storage-cross-tenant-block" for control "CCC.Core.CN05" assessment requirement "AR03" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"2s
Then "{result}" is true32µs
📎 Attachments:
policy-result-object-storage-cross-tenant-block.json
View JSON (2752 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN05/AR03/object-storage-cross-tenant-block/gcp.yaml",
  "name": "GCP Cloud Storage Cross-Tenant Access Block",
  "service_type": "object-storage",
  "requirement_text": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.\n",
  "validity_score": 6,
  "validity_commentary": "Cross-tenant (cross-project) access in GCP Storage is granted via IAM policy bindings with principals from other projects (e.g. serviceAccount:...@other-project.iam.gserviceaccount.com). This query checks the bucket IAM policy and validates cross-project members are in permitted-project-ids. Strengths: - Directly queries bucket IAM policy - Identifies serviceAccount members from other projects - Uses permitted-project-ids for explicit allowlist Limitations: - user: and group: members from outside the project not analyzed - Organization-level bindings are not checked\n",
  "query_template": "BINDINGS=$(gcloud storage buckets get-iam-policy gs://${ResourceName} --project=${GcpProjectId} --format=\"json(bindings)\" 2\u003e/dev/null || echo '{\"bindings\":[]}')\necho \"$BINDINGS\" | jq --arg p \"${GcpProjectId}\" '{\n  crossProjectIds: [\n    .bindings[]?.members[]? |\n    select(startswith(\"serviceAccount:\")) |\n    capture(\"serviceAccount:(?\u003csa\u003e[^@]+)@(?\u003cproj\u003e[^.]+)\\\\.iam\\\\.gserviceaccount\\\\.com\") |\n    select(.proj != $p) | .proj\n  ] | unique\n}' 2\u003e/dev/null || echo '{\"crossProjectIds\": []}'\n",
  "query_executed": "BINDINGS=$(gcloud storage buckets get-iam-policy gs://ccc-test-bucket-20260526t102300z --project=nodal-time-474015-p5 --format=\"json(bindings)\" 2\u003e/dev/null || echo '{\"bindings\":[]}')\necho \"$BINDINGS\" | jq --arg p \"nodal-time-474015-p5\" '{\n  crossProjectIds: [\n    .bindings[]?.members[]? |\n    select(startswith(\"serviceAccount:\")) |\n    capture(\"serviceAccount:(?\u003csa\u003e[^@]+)@(?\u003cproj\u003e[^.]+)\\\\.iam\\\\.gserviceaccount\\\\.com\") |\n    select(.proj != $p) | .proj\n  ] | unique\n}' 2\u003e/dev/null || echo '{\"crossProjectIds\": []}'\n",
  "query_output": "{\n  \"crossProjectIds\": []\n}\n",
  "passed": true,
  "rule_results": [
    {
      "jsonpath": "$.crossProjectIds",
      "expected_values": [],
      "validation_rule": "",
      "description": "Validates that cross-project service account members are in permitted-project-ids. Empty permitted = no cross-project allowed.\n",
      "actual_value": "[]",
      "passed": true
    }
  ]
}
Feature: CCC.Core.CN05.AR04 - Block Unauthorized External Data Requests
Scenario: External unauthorized data requests are blocked @PerService @CCC.Core @CCC.Core.CN05 @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"58µs
When I attempt policy check "object-storage-block-public-read" for control "CCC.Core.CN05" assessment requirement "AR04" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"862ms
policy check failed: GCP Cloud Storage Block External Unauthorized Data Requests: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true28µs
📎 Attachments:
policy-result-object-storage-block-public-read.json
View JSON (1646 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN05/AR04/object-storage-block-public-read/gcp.yaml",
  "name": "GCP Cloud Storage Block External Unauthorized Data Requests",
  "service_type": "object-storage",
  "requirement_text": "Data requests from outside the trust perimeter MUST be blocked so that data exfiltration is prevented. Only authorised identities may read data.\n",
  "validity_score": 8,
  "validity_commentary": "This query validates that GCP Cloud Storage has public access prevention enabled. When set to 'enforced' or 'inherited', the bucket cannot grant public read access via IAM or ACLs, blocking external unauthorized data requests. Strengths: - Prevents allUsers and allAuthenticatedUsers read access when enforced - Cannot be overridden by IAM policy or ACL changes - Aligns with Google security best practices Limitations: - Does not validate network-level restrictions - 'inherited' uses org-level policy; org should restrict public access - Behavioral testing verifies unauthorized read is blocked at runtime\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(iamConfiguration.publicAccessPrevention)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(iamConfiguration.publicAccessPrevention)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN05.AR05 - Hide Service Existence from External Requests
Scenario: External requests do not reveal service existence @PerService @CCC.Core @CCC.Core.CN05 @tlp-red @Policy @NotTested @object-storage
Given a cloud api for "{Instance}" in "api"48µs
Then no-op required24µs
Feature: CCC.Core.CN05.AR06 - Block All Unauthorized Requests
Scenario: Service prevents data read by user with no access @PerService @CCC.Core @CCC.Core.CN05 @tlp-green @tlp-amber @tlp-red @Destructive @Behavioural @Duplicate @object-storage
Given a cloud api for "{Instance}" in "api"36µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"42µs
And I refer to "{result}" as "storage"25µs
And I call "{api}" with "GetServiceAPI" using argument "iam"19µs
And I refer to "{result}" as "iamService"17µs
Then no-op required16µs
Scenario: All unauthorized requests are blocked @PerService @CCC.Core @CCC.Core.CN05 @tlp-green @tlp-amber @tlp-red @Policy @Duplicate @object-storage
Given a cloud api for "{Instance}" in "api"32µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"36µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"20µs
And I refer to "{result}" as "iamService"16µs
Then no-op required17µs
Feature: CCC.Core.CN06.AR01 - Resource Location Compliance
Scenario: Object storage region compliance @PerService @CCC.Core @CCC.Core.CN06 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"34µs
When I attempt policy check "object-storage-region" for control "CCC.Core.CN06" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"875ms
policy check failed: GCP Cloud Storage Bucket Region Compliance: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true26µs
📎 Attachments:
policy-result-object-storage-region.json
View JSON (1347 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN06/AR01/object-storage-region/gcp.yaml",
  "name": "GCP Cloud Storage Bucket Region Compliance",
  "service_type": "object-storage",
  "requirement_text": "When the service is running, its region and availability zone MUST be included  in a list of explicitly trusted or approved locations within the trust perimeter.\n",
  "validity_score": 8,
  "validity_commentary": "This query validates that GCP Cloud Storage buckets are deployed in approved locations. GCS supports regional, dual-region, and multi-region locations. Strengths: - Directly queries bucket location - Bucket location cannot be changed after creation - Easy to validate against an approved location list Limitations: - Approved locations must be defined externally - Multi-region buckets span multiple locations\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Resource region can be retrieved for compliance verification @PerService @CCC.Core @CCC.Core.CN06 @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage @vpc
Given a cloud api for "{Instance}" in "api"48µs
Given I call "{api}" with "GetServiceAPI" using argument "{ServiceType}"47µs
And I refer to "{result}" as "theService"16µs
When I call "{theService}" with "GetResourceRegion" using argument "{ResourceName}"33µs
Then "{result}" is not an error24µs
expected {result} to not be an error, but got: not yet implemented
And I refer to "{result}" as "region"17µs
And I attach "{region}" to the test output as "Resource Region"22µs
Then "{PermittedRegions}" is an array of objects with at least the following contents16µs
value
{region}
Feature: CCC.Core.CN06.AR02 - Child Resource Location Compliance
Scenario: Child resource region compliance @PerService @CCC.Core @CCC.Core.CN06 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"43µs
Then no-op required26µs
Scenario: Child resource region compliance @PerService @CCC.Core @CCC.Core.CN06 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"43µs
Then no-op required30µs
Feature: CCC.Core.CN07.AR01 - Publish Enumeration Activity Events
Scenario: Enumeration activities publish events to monitored channels @PerService @CCC.Core @CCC.Core.CN07 @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"43µs
When I attempt policy check "enumeration-monitoring-policy" for control "CCC.Core.CN07" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"870ms
policy check failed: GCP Enumeration Monitoring Policy Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true32µs
📎 Attachments:
policy-result-enumeration-monitoring-policy.json
View JSON (1037 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN07/AR01/enumeration-monitoring-policy/gcp.yaml",
  "name": "GCP Enumeration Monitoring Policy Check",
  "service_type": "object-storage",
  "requirement_text": "Enumeration activities must be monitored and generate events that can be sent to monitored channels.\n",
  "validity_score": 8,
  "validity_commentary": "This query validates that at least one log sink exists for the project, which allows logs to be exported to monitored channels like Pub/Sub, BigQuery, or a separate Logging project.\n",
  "query_template": "gcloud logging sinks list --project ${GcpProjectId} --format=json\n",
  "query_executed": "gcloud logging sinks list --project nodal-time-474015-p5 --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Enumeration event publishing cannot be tested automatically @PerService @CCC.Core @CCC.Core.CN07 @tlp-amber @tlp-red @Behavioural @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"40µs
Then no-op required29µs
Feature: CCC.Core.CN07.AR02 - Log Enumeration Activities
Scenario: Enumeration activities are logged @PerService @CCC.Core @CCC.Core.CN07 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"30µs
When I attempt policy check "enumeration-logging-policy" for control "CCC.Core.CN07" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"872ms
policy check failed: GCP Cloud Storage Enumeration Logging Policy Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true22µs
📎 Attachments:
policy-result-enumeration-logging-policy.json
View JSON (886 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN07/AR02/enumeration-logging-policy/gcp.yaml",
  "name": "GCP Cloud Storage Enumeration Logging Policy Check",
  "service_type": "object-storage",
  "requirement_text": "Enumeration activities must be logged.\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that bucket-level logging is enabled.\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Enumeration logging cannot be verified automatically @PerService @CCC.Core @CCC.Core.CN07 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"56µs
Then no-op required30µs
Feature: CCC.Core.CN08.AR01 - Data Replication and Redundancy
Scenario: Object storage replication compliance @PerService @CCC.Core @CCC.Core.CN08 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"45µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"41µs
And I refer to "{result}" as "storage"15µs
When I attempt policy check "object-storage-replication" for control "CCC.Core.CN08" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"864ms
policy check failed: GCP Cloud Storage Multi-Region/Dual-Region Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true27µs
📎 Attachments:
policy-result-object-storage-replication.json
View JSON (1394 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN08/AR01/object-storage-replication/gcp.yaml",
  "name": "GCP Cloud Storage Multi-Region/Dual-Region Configuration",
  "service_type": "object-storage",
  "requirement_text": "When data is created or modified, the data MUST have a complete and recoverable  duplicate that is stored in a physically separate data center.\n",
  "validity_score": 8,
  "validity_commentary": "This query validates GCP Cloud Storage replication through multi-region or dual-region bucket configuration. GCP provides automatic geo-redundancy for multi-region and dual-region buckets. Strengths: - Replication is automatic and synchronous - Multi-region provides geographic redundancy - Turbo replication available for dual-region Limitations: - Regional buckets do not provide geo-redundancy - Cross-bucket replication requires separate configuration\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Bucket data is replicated to physically separate locations @PerService @CCC.Core @CCC.Core.CN08 @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"48µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"49µs
And I refer to "{result}" as "storage"36µs
When I call "{storage}" with "GetReplicationStatus" using argument "{ResourceName}"55µs
And I refer to "{result}" as "replicationStatus"20µs
And I refer to "{replicationStatus.Locations}" as "locations"31µs
And I attach "{replicationStatus}" to the test output as "Replication Status"32µs
Then "{locations}" is an array of objects with length "2"37µs
field {locations} is not an array
And "{PermittedRegions}" is an array of objects with at least the following contents44µs
value
{locations[0]}
And "{PermittedRegions}" is an array of objects with at least the following contents23µs
value
{locations[1]}
📎 Attachments:
Replication Status
View Content (19 bytes)
not yet implemented
Feature: CCC.Core.CN08.AR02 - Replication Status Visibility
Scenario: Object storage replication status is visible @PerService @CCC.Core @CCC.Core.CN08 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"42µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"41µs
And I refer to "{result}" as "storage"30µs
When I attempt policy check "object-storage-replication-status" for control "CCC.Core.CN08" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"872ms
policy check failed: GCP Cloud Storage Replication Status Visibility: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true26µs
📎 Attachments:
policy-result-object-storage-replication-status.json
View JSON (1418 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN08/AR02/object-storage-replication-status/gcp.yaml",
  "name": "GCP Cloud Storage Replication Status Visibility",
  "service_type": "object-storage",
  "requirement_text": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that GCP Cloud Storage bucket replication information is visible. GCP provides location and replication type information. Strengths: - Location type indicates replication configuration - Multi-region/dual-region locations are automatically replicated - Turbo replication provides faster sync for dual-region Limitations: - GCP does not expose real-time replication lag metrics - Object-level replication status is not available\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Replication status can be retrieved for monitoring @PerService @CCC.Core @CCC.Core.CN08 @tlp-green @tlp-amber @tlp-red @Behavioural @object-storage
Given a cloud api for "{Instance}" in "api"54µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"33µs
And I refer to "{result}" as "storage"14µs
When I call "{storage}" with "GetReplicationStatus" using argument "{ResourceName}"35µs
And I refer to "{result}" as "replicationStatus"16µs
And I attach "{replicationStatus}" to the test output as "Replication Status"31µs
And I refer to "{replicationStatus.Locations}" as "locations"35µs
Then "{locations}" is an array of objects with at least the following contents18µs
value
{ReplicationLocations[0]}
{ReplicationLocations[1]}
field {locations} is not an array
📎 Attachments:
Replication Status
View Content (19 bytes)
not yet implemented
Feature: CCC.Core.CN09.AR01 - Access Logging Separation
Scenario: Object storage access logging compliance @PerService @CCC.Core @CCC.Core.CN09 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"71µs
When I attempt policy check "object-storage-access-logging" for control "CCC.Core.CN09" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"864ms
policy check failed: GCP Cloud Storage Access Logging Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true27µs
📎 Attachments:
policy-result-object-storage-access-logging.json
View JSON (1396 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN09/AR01/object-storage-access-logging/gcp.yaml",
  "name": "GCP Cloud Storage Access Logging Configuration",
  "service_type": "object-storage",
  "requirement_text": "When the service is operational, its logs and any child resource logs MUST NOT  be accessible from the resource they record access to.\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that GCP Cloud Storage access logging is configured to write to a separate bucket. GCP also supports Cloud Audit Logs. Strengths: - Validates logging is enabled and configured - Target bucket separation ensures logs are not accessible from source - Cloud Audit Logs provide additional logging Limitations: - Does not validate Cloud Audit Logs configuration - Does not verify target bucket permissions - Legacy logging (bucket-level) is being deprecated\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.Core.CN09.AR02 - Logs Cannot Be Disabled
Scenario: Disabling logs requires disabling the resource @PerService @CCC.Core @CCC.Core.CN09 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"39µs
Then no-op required30µs
Feature: CCC.Core.CN09.AR03 - Log Redirection Requires Service Halt
Scenario: Redirecting logs requires halting the resource @PerService @CCC.Core @CCC.Core.CN09 @tlp-amber @tlp-red @Policy @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"32µs
Then no-op required28µs
Feature: CCC.Core.CN10.AR01 - Replication Destination Trust
Scenario: Object storage replication destination compliance @PerService @CCC.Core @CCC.Core.CN10 @tlp-green @tlp-amber @tlp-red @Policy @object-storage
Given a cloud api for "{Instance}" in "api"31µs
When I attempt policy check "object-storage-replication-destination" for control "CCC.Core.CN10" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"886ms
policy check failed: GCP Cloud Storage Replication Destination Validation: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true30µs
📎 Attachments:
policy-result-object-storage-replication-destination.json
View JSON (1431 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.Core/CCC.Core.CN10/AR01/object-storage-replication-destination/gcp.yaml",
  "name": "GCP Cloud Storage Replication Destination Validation",
  "service_type": "object-storage",
  "requirement_text": "When data is replicated, the service MUST ensure that replication only occurs  to destinations that are explicitly included within the defined trust perimeter.\n",
  "validity_score": 7,
  "validity_commentary": "This query validates that GCP Cloud Storage bucket locations are within approved regions. For multi-region/dual-region buckets, GCP automatically determines replication destinations. Strengths: - Location type and location are directly queryable - Multi-region locations have known member regions - Can validate against approved location list Limitations: - GCP does not allow custom replication destination selection - Dual-region specific regions may need validation\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Scenario: Replication destination trust cannot be verified automatically @PerService @CCC.Core @CCC.Core.CN10 @tlp-green @tlp-amber @tlp-red @Behavioural @NotTestable @object-storage
Given a cloud api for "{Instance}" in "api"55µs
Then no-op required34µs
Feature: CCC.ObjStor.CN01.AR01
Scenario: Service prevents reading bucket with no access @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"40µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"45µs
And I refer to "{result}" as "storage"29µs
And I call "{api}" with "GetServiceAPI" using argument "iam"32µs
And I refer to "{result}" as "iamService"19µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-access", "{UID}", and "none"1s
And I refer to "{result}" as "testUserNoAccess"28µs
And I attach "{result}" to the test output as "no-access-user-identity.json"35µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"50µs
And "{result}" is not an error45µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"21µs
When I call "{userStorage}" with "ListObjects" using argument "{ResourceName}"20µs
Then "{result}" is an error16µs
And I attach "{result}" to the test output as "no-access-list-error.txt"18µs
📎 Attachments:
no-access-user-identity.json
View Content (238 bytes)
failed to create service account key for test-user-no-access: rpc error: code = NotFound desc = Service account projects/nodal-time-474015-p5/serviceAccounts/test-user-no-access@nodal-time-474015-p5.iam.gserviceaccount.com does not exist.
Scenario: Service allows reading bucket with read access @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"45µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"45µs
And I refer to "{result}" as "storage"28µs
And I call "{api}" with "GetServiceAPI" using argument "iam"23µs
And I refer to "{result}" as "iamService"23µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read", "{UID}", and "read"132ms
And I refer to "{result}" as "testUserRead"27µs
And I attach "{result}" to the test output as "read-user-identity.json"41µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{true}"52µs
And "{result}" is not an error47µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I attach "{result}" to the test output as "read-storage-service.json"18µs
And I refer to "{result}" as "userStorage"19µs
When I call "{userStorage}" with "ListObjects" using argument "{ResourceName}"19µs
Then "{result}" is not an error18µs
And I attach "{result}" to the test output as "read-list-objects-result.json"17µs
📎 Attachments:
read-user-identity.json
View Content (227 bytes)
failed to create service account test-user-read: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Test policy for bucket access control @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Policy
Given a cloud api for "{Instance}" in "api"68µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"34µs
And I refer to "{result}" as "storage"17µs
And I call "{api}" with "GetServiceAPI" using argument "iam"20µs
And I refer to "{result}" as "iamService"17µs
When I attempt policy check "no-public-access" for control "CCC.ObjStor.CN01" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"876ms
policy check failed: GCP Cloud Storage Block Public Access Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true31µs
📎 Attachments:
policy-result-no-public-access.json
View JSON (1338 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN01/AR01/no-public-access/gcp.yaml",
  "name": "GCP Cloud Storage Block Public Access Check",
  "service_type": "object-storage",
  "requirement_text": "The service MUST enforce access control so that only authorised identities can read, list, write, or create objects and buckets.\n",
  "validity_score": 10,
  "validity_commentary": "This query validates that Uniform Bucket-Level Access is enabled on the GCP bucket, which prevents unauthenticated or ACL-based public access. Strengths: - Directly verifies the IAM configuration for uniform access - When UBLA is enabled, only IAM bindings control access — no public ACLs - Consistent with GCP security best practices\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(iamConfiguration.uniformBucketLevelAccess)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(iamConfiguration.uniformBucketLevelAccess)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN01.AR02
Scenario: Service prevents reading object with no access @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"40µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"42µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"30µs
And I refer to "{result}" as "iamService"27µs
And I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "test content"131ms
And "{result}" is not an error24µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-access", "{UID}", and "none"153ms
And I refer to "{result}" as "testUserNoAccess"26µs
And I attach "{result}" to the test output as "no-access-user-identity.json"39µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"48µs
And "{result}" is not an error26µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"19µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"21µs
Then "{result}" is an error16µs
And I attach "{result}" to the test output as "no-access-read-object-error.txt"23µs
📎 Attachments:
no-access-user-identity.json
View Content (232 bytes)
failed to create service account test-user-no-access: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Service allows reading object with read access @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"66µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"35µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"22µs
And I refer to "{result}" as "iamService"26µs
And I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "test content"148ms
And "{result}" is not an error29µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read", "{UID}", and "read"1s
And I refer to "{result}" as "testUserRead"34µs
And I attach "{result}" to the test output as "read-user-identity.json"40µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{true}"55µs
And "{result}" is not an error34µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I attach "{result}" to the test output as "read-storage-service.json"19µs
And I refer to "{result}" as "userStorage"18µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"17µs
Then "{result}" is not an error23µs
And I attach "{result}" to the test output as "read-read-object-result.json"15µs
📎 Attachments:
read-user-identity.json
View Content (228 bytes)
failed to create service account key for test-user-read: rpc error: code = NotFound desc = Service account projects/nodal-time-474015-p5/serviceAccounts/test-user-read@nodal-time-474015-p5.iam.gserviceaccount.com does not exist.
Scenario: All unauthorized requests are blocked @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Policy
Given a cloud api for "{Instance}" in "api"47µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"28µs
And I refer to "{result}" as "storage"14µs
And I call "{api}" with "GetServiceAPI" using argument "iam"36µs
And I refer to "{result}" as "iamService"16µs
And I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "test content"131ms
And "{result}" is not an error27µs
When I attempt policy check "object-storage-no-public-principals" for control "CCC.ObjStor.CN01" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"900ms
Then "{result}" is true38µs
📎 Attachments:
policy-result-object-storage-no-public-principals.json
View JSON (1943 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN01/AR02/object-storage-no-public-principals/gcp.yaml",
  "name": "GCP Cloud Storage IAM in Use",
  "service_type": "object-storage",
  "requirement_text": "All unauthorized requests MUST be blocked. Access MUST be controlled by IAM.\n",
  "validity_score": 7,
  "validity_commentary": "ObjStor.CN01.AR01 already validates no-public-access. This check validates that IAM bindings exist on the bucket, proving access control is identity-based rather than public. At least one binding indicates IAM is in use. Strengths: - Confirms IAM is configured for the bucket - Bindings scope access to specific identities (user, group, service account) Limitations: - Does not validate least-privilege bindings - Inherited project-level bindings may not appear in bucket policy - Behavioral testing verifies unauthorized access is blocked at runtime\n",
  "query_template": "POLICY=$(gcloud storage buckets get-iam-policy gs://${ResourceName} --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_executed": "POLICY=$(gcloud storage buckets get-iam-policy gs://ccc-test-bucket-20260526t102300z --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_output": "{\"iamInUse\": 4}\n",
  "passed": true,
  "rule_results": [
    {
      "jsonpath": "$.iamInUse",
      "expected_values": [],
      "validation_rule": "^[1-9][0-9]*$",
      "description": "Validates that at least one IAM binding exists on the bucket. IAM is the required access control mechanism; no bindings indicates access may not be properly scoped.\n",
      "actual_value": "[4]",
      "passed": true
    }
  ]
}
Feature: CCC.ObjStor.CN01.AR03
Scenario: Service prevents creating bucket with no access @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"39µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"44µs
And I refer to "{result}" as "storage"30µs
And I call "{api}" with "GetServiceAPI" using argument "iam"34µs
And I refer to "{result}" as "iamService"30µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-access", "{UID}", and "none"145ms
And I refer to "{result}" as "testUserNoAccess"29µs
And I attach "{result}" to the test output as "no-access-user-identity.json"40µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"60µs
And "{result}" is not an error23µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"17µs
When I call "{userStorage}" with "CreateBucket" using argument "test-bucket-no-access"18µs
Then "{result}" is an error17µs
And I attach "{result}" to the test output as "no-access-create-bucket-error.txt"16µs
📎 Attachments:
no-access-user-identity.json
View Content (232 bytes)
failed to create service account test-user-no-access: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Service allows creating bucket with write access @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"46µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"36µs
And I refer to "{result}" as "storage"25µs
And I call "{api}" with "GetServiceAPI" using argument "iam"21µs
And I refer to "{result}" as "iamService"22µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write", "{UID}", and "write"106ms
And I refer to "{result}" as "testUserWrite"29µs
And I attach "{result}" to the test output as "write-user-identity.json"37µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"59µs
And "{result}" is not an error50µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I attach "{result}" to the test output as "write-storage-service.json"25µs
And I refer to "{result}" as "userStorage"44µs
When I call "{userStorage}" with "CreateBucket" using argument "test-bucket-write"19µs
Then "{result}" is not an error22µs
And I attach "{result}" to the test output as "write-create-bucket-result.json"17µs
And I call "{storage}" with "DeleteBucket" using argument "{result.ID}"19µs
📎 Attachments:
write-user-identity.json
View Content (228 bytes)
failed to create service account test-user-write: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: All unauthorized requests are blocked @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Policy
Given a cloud api for "{Instance}" in "api"37µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"41µs
And I refer to "{result}" as "storage"17µs
And I call "{api}" with "GetServiceAPI" using argument "iam"20µs
And I refer to "{result}" as "iamService"23µs
When I attempt policy check "object-storage-no-public-principals" for control "CCC.ObjStor.CN01" assessment requirement "AR03" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"826ms
Then "{result}" is true36µs
📎 Attachments:
policy-result-object-storage-no-public-principals.json
View JSON (1943 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN01/AR03/object-storage-no-public-principals/gcp.yaml",
  "name": "GCP Cloud Storage IAM in Use",
  "service_type": "object-storage",
  "requirement_text": "All unauthorized requests MUST be blocked. Access MUST be controlled by IAM.\n",
  "validity_score": 7,
  "validity_commentary": "ObjStor.CN01.AR01 already validates no-public-access. This check validates that IAM bindings exist on the bucket, proving access control is identity-based rather than public. At least one binding indicates IAM is in use. Strengths: - Confirms IAM is configured for the bucket - Bindings scope access to specific identities (user, group, service account) Limitations: - Does not validate least-privilege bindings - Inherited project-level bindings may not appear in bucket policy - Behavioral testing verifies unauthorized access is blocked at runtime\n",
  "query_template": "POLICY=$(gcloud storage buckets get-iam-policy gs://${ResourceName} --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_executed": "POLICY=$(gcloud storage buckets get-iam-policy gs://ccc-test-bucket-20260526t102300z --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_output": "{\"iamInUse\": 4}\n",
  "passed": true,
  "rule_results": [
    {
      "jsonpath": "$.iamInUse",
      "expected_values": [],
      "validation_rule": "^[1-9][0-9]*$",
      "description": "Validates that at least one IAM binding exists on the bucket. IAM is the required access control mechanism; no bindings indicates access may not be properly scoped.\n",
      "actual_value": "[4]",
      "passed": true
    }
  ]
}
Feature: CCC.ObjStor.CN01.AR04
Scenario: Service prevents writing object with read-only access @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"44µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"42µs
And I refer to "{result}" as "storage"27µs
And "{result}" is not an error33µs
And I call "{api}" with "GetServiceAPI" using argument "iam"37µs
And I refer to "{result}" as "iamService"18µs
And "{result}" is not an error22µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read", "{UID}", and "read"122ms
And I refer to "{result}" as "testUserRead"32µs
And I attach "{result}" to the test output as "read-user-identity.json"35µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{true}"56µs
And "{result}" is not an error32µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"15µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "test-write-object={Timestamp}.txt", and "test content"18µs
Then "{result}" is an error26µs
And I attach "{result}" to the test output as "read-create-object-error.txt"17µs
📎 Attachments:
read-user-identity.json
View Content (227 bytes)
failed to create service account test-user-read: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Service allows writing object with write access @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Behavioural
Given a cloud api for "{Instance}" in "api"42µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"40µs
And I refer to "{result}" as "storage"24µs
And "{result}" is not an error15µs
And I call "{api}" with "GetServiceAPI" using argument "iam"18µs
And I refer to "{result}" as "iamService"17µs
And "{result}" is not an error15µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write", "{UID}", and "write"107ms
And I refer to "{result}" as "testUserWrite"23µs
And I attach "{result}" to the test output as "write-user-identity.json"27µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"40µs
And "{result}" is not an error26µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I attach "{result}" to the test output as "write-storage-service.json"24µs
And I refer to "{result}" as "userStorage"23µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "test-write-object={Timestamp}.txt", and "test content"31µs
Then "{result}" is not an error24µs
And I attach "{result}" to the test output as "write-create-object-result.json"26µs
📎 Attachments:
write-user-identity.json
View Content (228 bytes)
failed to create service account test-user-write: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: All unauthorized requests are blocked @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN01 @Policy
Given a cloud api for "{Instance}" in "api"35µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"36µs
And I refer to "{result}" as "storage"28µs
And "{result}" is not an error28µs
And I call "{api}" with "GetServiceAPI" using argument "iam"30µs
And I refer to "{result}" as "iamService"16µs
And "{result}" is not an error16µs
When I attempt policy check "object-storage-no-public-principals" for control "CCC.ObjStor.CN01" assessment requirement "AR04" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"874ms
Then "{result}" is true33µs
📎 Attachments:
policy-result-object-storage-no-public-principals.json
View JSON (1943 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN01/AR04/object-storage-no-public-principals/gcp.yaml",
  "name": "GCP Cloud Storage IAM in Use",
  "service_type": "object-storage",
  "requirement_text": "All unauthorized requests MUST be blocked. Access MUST be controlled by IAM.\n",
  "validity_score": 7,
  "validity_commentary": "ObjStor.CN01.AR01 already validates no-public-access. This check validates that IAM bindings exist on the bucket, proving access control is identity-based rather than public. At least one binding indicates IAM is in use. Strengths: - Confirms IAM is configured for the bucket - Bindings scope access to specific identities (user, group, service account) Limitations: - Does not validate least-privilege bindings - Inherited project-level bindings may not appear in bucket policy - Behavioral testing verifies unauthorized access is blocked at runtime\n",
  "query_template": "POLICY=$(gcloud storage buckets get-iam-policy gs://${ResourceName} --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_executed": "POLICY=$(gcloud storage buckets get-iam-policy gs://ccc-test-bucket-20260526t102300z --format=json 2\u003e/dev/null || echo \"{}\")\nCOUNT=$(echo \"$POLICY\" | jq -r '.bindings | length' 2\u003e/dev/null || echo \"0\")\necho \"{\\\"iamInUse\\\": $COUNT}\"\n",
  "query_output": "{\"iamInUse\": 4}\n",
  "passed": true,
  "rule_results": [
    {
      "jsonpath": "$.iamInUse",
      "expected_values": [],
      "validation_rule": "^[1-9][0-9]*$",
      "description": "Validates that at least one IAM binding exists on the bucket. IAM is the required access control mechanism; no bindings indicates access may not be properly scoped.\n",
      "actual_value": "[4]",
      "passed": true
    }
  ]
}
Feature: CCC.ObjStor.CN02.AR01 - Uniform Bucket-Level Access (Consistent Allow)
Scenario: Service enforces uniform bucket-level access by rejecting object-level permissions @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN02 @Behavioural
Given a cloud api for "{Instance}" in "api"41µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"59µs
And I refer to "{result}" as "storage"26µs
And I call "{api}" with "GetServiceAPI" using argument "iam"35µs
And I refer to "{result}" as "iamService"23µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "test data"141ms
Then "{result}" is not an error24µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read", "{UID}", and "read"139ms
And I refer to "{result}" as "testUserRead"33µs
And I attach "{result}" to the test output as "read-user-identity.json"30µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{true}"52µs
And "{result}" is not an error36µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"23µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"23µs
Then "{result}" is not an error20µs
When I call "{storage}" with "SetObjectPermission" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "none"27µs
Then "{result}" is an error22µs
And I attach "{result}" to the test output as "set-object-permission-error.txt"18µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"19µs
Then "{result}" is not an error15µs
📎 Attachments:
read-user-identity.json
View Content (227 bytes)
failed to create service account test-user-read: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Test policy for uniform access @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN02 @Policy
Given a cloud api for "{Instance}" in "api"41µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"41µs
And I refer to "{result}" as "storage"28µs
And I call "{api}" with "GetServiceAPI" using argument "iam"33µs
And I refer to "{result}" as "iamService"27µs
When I attempt policy check "uniform-bucket-level-access" for control "CCC.ObjStor.CN02" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"869ms
policy check failed: GCP Cloud Storage Uniform Bucket-Level Access Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true30µs
📎 Attachments:
policy-result-uniform-bucket-level-access.json
View JSON (1290 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN02/AR01/uniform-bucket-level-access/gcp.yaml",
  "name": "GCP Cloud Storage Uniform Bucket-Level Access Check",
  "service_type": "object-storage",
  "requirement_text": "The service MUST enforce uniform bucket-level access, preventing ad-hoc  object-level permissions.\n",
  "validity_score": 10,
  "validity_commentary": "This query validates that Uniform Bucket-Level Access (UBLA) is enabled. UBLA ensures that only IAM policies govern access to the bucket and its objects. Strengths: - Directly queries the UBLA configuration - Guarantees no ad-hoc object ACLs can be used - Consistent with GCP security best practices\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(iamConfiguration.uniformBucketLevelAccess)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(iamConfiguration.uniformBucketLevelAccess)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN02.AR02 - Uniform Bucket-Level Access (Consistent Deny)
Scenario: Service enforces uniform bucket-level access denial @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN02 @Behavioural
Given a cloud api for "{Instance}" in "api"47µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"44µs
And I refer to "{result}" as "storage"42µs
And I call "{api}" with "GetServiceAPI" using argument "iam"33µs
And I refer to "{result}" as "iamService"25µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "test data"124ms
Then "{result}" is not an error25µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-no-access", "{UID}", and "none"160ms
And I refer to "{result}" as "testUserNoAccess"29µs
And I attach "{result}" to the test output as "no-access-user-identity.json"36µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserNoAccess}", and "{false}"119µs
And "{result}" is not an error39µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"17µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"16µs
Then "{result}" is an error17µs
When I call "{storage}" with "SetObjectPermission" using arguments "{ResourceName}", "test-object={Timestamp}.txt", and "read"19µs
Then "{result}" is an error14µs
And I attach "{result}" to the test output as "set-object-permission-error.txt"16µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "test-object={Timestamp}.txt"18µs
Then "{result}" is an error13µs
📎 Attachments:
no-access-user-identity.json
View Content (232 bytes)
failed to create service account test-user-no-access: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Uniform bucket-level access prevents object-level deny overrides @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN02 @Policy @Duplicate @object-storage
Given a cloud api for "{Instance}" in "api"38µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"40µs
And I refer to "{result}" as "storage"23µs
And I call "{api}" with "GetServiceAPI" using argument "iam"32µs
And I refer to "{result}" as "iamService"16µs
Then no-op required15µs
Feature: CCC.ObjStor.CN03.AR01 - Bucket Soft Delete and Recovery
Scenario: Service supports bucket soft delete and recovery @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN03 @Behavioural
Given a cloud api for "{Instance}" in "api"31µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"33µs
And I refer to "{result}" as "storage"22µs
When I call "{storage}" with "CreateBucket" using argument "ccc-test-soft-delete"670ms
Then "{result}" is not an error38µs
And I refer to "{result}" as "testBucket"29µs
And I attach "{result}" to the test output as "created-bucket.json"60µs
When I call "{storage}" with "DeleteBucket" using argument "ccc-test-soft-delete"346ms
Then "{result}" is not an error25µs
When I call "{storage}" with "ListDeletedBuckets"41µs
Then "{result}" is not an error23µs
expected {result} to not be an error, but got: GCS does not support bucket-level soft delete - bucket deletion is immediate
And I attach "{result}" to the test output as "deleted-buckets.json"54µs
And "{result}" should have length greater than "0"17µs
When I call "{storage}" with "RestoreBucket" using argument "ccc-test-soft-delete"16µs
Then "{result}" is not an error13µs
When I call "{storage}" with "ListBuckets"11µs
Then "{result}" is not an error16µs
And I attach "{result}" to the test output as "restored-buckets.json"13µs
When I call "{storage}" with "DeleteBucket" using argument "ccc-test-soft-delete"14µs
Then "{result}" is not an error14µs
📎 Attachments:
created-bucket.json
View JSON (82 bytes)
{"ID":"ccc-test-soft-delete","Name":"ccc-test-soft-delete","Region":"us-central1"}
Scenario: Test policy for bucket soft delete @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN03 @Policy
Given a cloud api for "{Instance}" in "api"73µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"52µs
And I refer to "{result}" as "storage"44µs
When I attempt policy check "bucket-soft-delete" for control "CCC.ObjStor.CN03" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"887ms
policy check failed: GCP Cloud Storage Soft Delete Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true18µs
📎 Attachments:
policy-result-bucket-soft-delete.json
View JSON (1384 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN03/AR01/bucket-soft-delete/gcp.yaml",
  "name": "GCP Cloud Storage Soft Delete Check",
  "service_type": "object-storage",
  "requirement_text": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.\n",
  "validity_score": 9,
  "validity_commentary": "GCP Cloud Storage supports bucket soft delete via the softDeletePolicy. This check validates that the soft delete retention duration is set to a non-zero value, ensuring deleted buckets and objects can be recovered. Strengths: - Directly checks the soft delete policy configuration - GCP soft delete is a native feature providing bucket-level recovery Limitations: - Does not verify the exact minimum retention duration required\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(softDeletePolicy)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(softDeletePolicy)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN03.AR02 - Immutable Bucket Retention Policy
Scenario: Service prevents modification of locked retention policy @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN03 @Behavioural
Given a cloud api for "{Instance}" in "api"70µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"42µs
And I refer to "{result}" as "storage"24µs
When I call "{storage}" with "GetBucketRetentionDurationDays" using argument "{ResourceName}"41ms
Then "{result}" is not an error26µs
And I refer to "{result}" as "originalRetention"30µs
And I attach "{result}" to the test output as "original-retention-days.txt"54µs
And "{result}" should be greater than "0"39µs
When I call "{storage}" with "SetBucketRetentionDurationDays" using arguments "{ResourceName}" and "1"131ms
Then "{result}" is an error49µs
expected {result} to be an error, got
And I attach "{result}" to the test output as "set-retention-error.txt"37µs
When I call "{storage}" with "GetBucketRetentionDurationDays" using argument "{ResourceName}"34µs
Then "{result}" is not an error31µs
And "{result}" should equal "{originalRetention}"33µs
📎 Attachments:
original-retention-days.txt
View JSON (1 bytes)
2
Scenario: Test policy for immutable bucket retention lock @PerService @object-storage @CCC.ObjStor @tlp-amber @tlp-red @CCC.ObjStor.CN03 @Policy
Given a cloud api for "{Instance}" in "api"46µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"51µs
And I refer to "{result}" as "storage"34µs
When I attempt policy check "bucket-retention-lock" for control "CCC.ObjStor.CN03" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"866ms
policy check failed: GCP Cloud Storage Retention Policy Lock Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true52µs
📎 Attachments:
policy-result-bucket-retention-lock.json
View JSON (1384 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN03/AR02/bucket-retention-lock/gcp.yaml",
  "name": "GCP Cloud Storage Retention Policy Lock Check",
  "service_type": "object-storage",
  "requirement_text": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.\n",
  "validity_score": 10,
  "validity_commentary": "This query validates that a retention policy is set and locked on the GCP bucket. A locked retention policy cannot be removed or shortened, even by project owners. Strengths: - Locking is an irreversible, immutable configuration - Directly checks both the presence and locked state of the policy - Consistent with GCP compliance best practices Limitations: - Does not validate the specific minimum retention period\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN04.AR01
Scenario: Service applies default retention policy to newly uploaded object @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"52µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"51µs
And I refer to "{result}" as "storage"19µs
And I call "{api}" with "GetServiceAPI" using argument "iam"20µs
And I refer to "{result}" as "iamService"13µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write", "{UID}", and "write"884ms
And I refer to "{result}" as "testUserWrite"36µs
And I attach "{result}" to the test output as "write-user-identity.json"69µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"91ms
And "{result}" is not an error27µs
expected {result} to not be an error, but got: credentials not ready: credentials not ready for GCS access: Get "https://storage.googleapis.com/storage/v1/b?alt=json&pageToken=&prefix=&prettyPrint=false&project=nodal-time-474015-p5&projection=full&returnPartialSuccess=false": auth: cannot fetch token: 400 Response: {"error":"invalid_grant","error_description":"Invalid JWT Signature."}
And I refer to "{result}" as "userStorage"17µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "test-retention-object={Timestamp}.txt", and "protected data"21µs
And I attach "{result}" to the test output as "uploaded-object.json"17µs
And I call "{userStorage}" with "GetObjectRetentionDurationDays" using arguments "{ResourceName}" and "test-retention-object={Timestamp}.txt"21µs
Then "{result}" should be greater than "1"17µs
📎 Attachments:
write-user-identity.json
View JSON (3020 bytes)
{"UserName":"test-user-write","Provider":"gcp","Credentials":{"client_email":"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com","email":"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com","private_key_id":"862e25e3202690e27c62ce2bc4a7606b214eb924","project_id":"nodal-time-474015-p5","service_account_key":"{\n  \"type\": \"service_account\",\n  \"project_id\": \"nodal-time-474015-p5\",\n  \"private_key_id\": \"862e25e3202690e27c62ce2bc4a7606b214eb924\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDR9fPGFF4BImwW\\nD91YZOpE045Hevh1L8NWkiHjmGD+bu7BzUv41vq/86qkn5/yV3SLI89Stnwi9M01\\ncJ+oqdNNx/eJ51QS3LrSRQAi+Cfy6iFapVyw6w006IJnUP29tgah/wuYBhSPR1Wi\\no36m7+AT0BlgYS/9ai8hw7ZfevSWCUIOE4rTY9fCl1k4hMdYTdZz3/yxHqiTGQMn\\ndYjaIVE159KvMQP7aW8sMpbhdFLmFp5BLE96OAQ0V1Jq8qR+ij2cQt12fisWnTZm\\nrJHpprk/0T36lJdQdnb5+F6+DPqM8Ay636a8hnFPk54mKR92+EEn3Gs9XvAJDqsC\\n2I24CWTfAgMBAAECggEAGLT4mraK2VdToMT9Jwm5B6BdfcvasO+N7QIFOuMTht1G\\n+0dNSVsC5tOloPmnuLzR2g28t98BfJuSClfWceKKGv0NBA1Ut2OCGHxGJ9dL3Cnx\\nAtmyrp76Tt+NeNrvAQQKg8Wfd6Q/hxy91wWmQb64f5xdYBoPq6JzKWX+b/3oCj+V\\n943PwFDoCPP4I/EMp+Vph1gWPvs2Xu0qCdiK14PWQCbYzPewTDHJAmWuNmeITyHb\\n3X7RgK1BlaRbtLaEO2SiKCyjYivaWAyhUj/zwuYRc5fp/mEIM6xryrGmy/7dTU8T\\nRgwoentL8IMdnRq+X1qqUMvinsaiiYco0nZx4/p7AQKBgQD3pRYGj2tthx3T9y9H\\nBvPJaWAoI2RirC//CNqN5qRozraKBaj73sWUa0rgGCVYa94KosjyINHX0TZ9zigj\\nXvr0wzcM4RM2RdeoZahNBRDxVVR5szYgnfpM8RtJpdDF2FuYIBoeO838wIgpOEmv\\nRHei3jzvMAkp0gqhA4sM+d/VSwKBgQDZC2M/0CoQJUzewH9wnkup1EV8ryPJ0Hxe\\ntVufEL5PTtt57geXYq3F5qh9jinXu74NzD2wOILHYM52TZSQdl6AuLAUE1GUBab4\\nQ+VDvGy9gQPAWh+SsLz6h1rojwSpJdQrq8lMzAOpR1/3k9YHOztAbhB/8njI3Xc2\\n0raFLUl2PQKBgDiQO3SqI3Zz6ys0BVdqzhoN+ImSc+ZZv+i3o/vPV3Qc6vKhklRd\\nMLHSw9pliXolwSSaw90SA/wQbCrWALL7icSIJjXJ3vKBh12OQp+87X7B57aYaV+P\\n1dDnLT1oI0RdQ6Z+hpirPkRh0XfgxGvE7rKDolVbmmwz7nuSbJs9I5P7AoGARZE+\\n2J9SPCaYgvVUY7Z5LhAZzaMdZ3xpwLmEinGFbkoqUuSWjlFUvY/3BXdhtgI5IpcK\\nVsdmM521z3mCWuN12vBXj7e5eCZvpDeu7o0glYUavLamVBBOIkbsPopIxiaX4P+I\\n4BKsQb/c5K//9AVqMnaU103SpR9HLM1RL1Kar0kCgYEAufcFQiktxojyGouLo9pD\\nRgxpF1gk/pmDqdCFvQZL3eULvFJXsExhGCcFOtJB6/EKk5Z4JzaBhZY1JreTk/9E\\n3wKPIXQDAAo3Xd0VXBRrCfIyuU0kmBIPqRsUS6FcryoDspze4ZF/58IadasJz7Sq\\nc1YHLcnUFU575G7T4G4OrFA=\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"client_id\": \"114093962834554122395\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/test-user-write%40nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n","unique_id":"114093962834554122395"},"Policy":"{\"user\": \"test-user-write\", \"service\": \"projects/nodal-time-474015-p5/buckets/ccc-test-bucket-20260526t102300z\", \"level\": \"write\", \"role\": \"roles/editor\"}"}
Scenario: Service enforces retention policy on newly created objects @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"63µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"45µs
And I refer to "{result}" as "storage"28µs
And I call "{api}" with "GetServiceAPI" using argument "iam"20µs
And I refer to "{result}" as "iamService"21µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "immediate-delete-test={Timestamp}.txt", and "test content"134ms
Then "{result}" is not an error26µs
When I call "{storage}" with "DeleteObject" using arguments "{ResourceName}" and "immediate-delete-test={Timestamp}.txt"68ms
Then "{result}" is an error31µs
expected {result} to be an error, got
And I attach "{result}" to the test output as "immediate-delete-error.txt"20µs
Scenario: Service validates retention period meets minimum requirements @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"37µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"27µs
And I refer to "{result}" as "storage"25µs
And I call "{api}" with "GetServiceAPI" using argument "iam"33µs
And I refer to "{result}" as "iamService"21µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "retention-period-test={Timestamp}.txt", and "compliance data"118ms
And I call "{storage}" with "GetObjectRetentionDurationDays" using arguments "{ResourceName}" and "retention-period-test={Timestamp}.txt"83ms
Then "{result}" should be greater than "1"39µs
expected {result} (1) to be greater than 1
And I attach "{result}" to the test output as "retention-period-days.json"24µs
Scenario: Test policy for default object retention @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Policy
Given a cloud api for "{Instance}" in "api"40µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"43µs
And I refer to "{result}" as "storage"27µs
And I call "{api}" with "GetServiceAPI" using argument "iam"35µs
And I refer to "{result}" as "iamService"19µs
When I attempt policy check "object-default-retention" for control "CCC.ObjStor.CN04" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"886ms
policy check failed: GCP Cloud Storage Default Object Retention Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true33µs
📎 Attachments:
policy-result-object-default-retention.json
View JSON (1482 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN04/AR01/object-default-retention/gcp.yaml",
  "name": "GCP Cloud Storage Default Object Retention Check",
  "service_type": "object-storage",
  "requirement_text": "Objects MUST automatically receive a default retention policy upon upload, protecting critical data from premature deletion or modification.\n",
  "validity_score": 9,
  "validity_commentary": "This query validates that a default object retention policy is configured on the GCP Cloud Storage bucket. GCP's default object retention ensures all objects created in the bucket automatically inherit the retention duration. Strengths: - Default retention is applied at bucket level, covering all new objects - Directly queries the bucket retention policy configuration Limitations: - Does not validate whether the policy is locked (see CN03.AR02) - Does not validate the specific minimum retention duration\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN04.AR02
Scenario: Service prevents object deletion by write user during retention period @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"51µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"43µs
And I refer to "{result}" as "storage"19µs
And I call "{api}" with "GetServiceAPI" using argument "iam"21µs
And I refer to "{result}" as "iamService"15µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write", "{UID}", and "write"35µs
And I refer to "{result}" as "testUserWrite"25µs
And I attach "{result}" to the test output as "write-user-identity.json"53µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"309ms
And "{result}" is not an error30µs
expected {result} to not be an error, but got: credentials not ready: credentials not ready for GCS access: googleapi: Error 403: test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com does not have storage.buckets.list access to the Google Cloud project. Permission 'storage.buckets.list' denied on resource (or it may not exist)., forbidden
And I refer to "{result}" as "userStorage"17µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "protected-object={Timestamp}.txt", and "immutable data"20µs
Then "{result}" is not an error15µs
And I attach "{result}" to the test output as "protected-object.json"17µs
When I call "{userStorage}" with "DeleteObject" using arguments "{ResourceName}" and "protected-object={Timestamp}.txt"18µs
Then "{result}" is an error14µs
And I attach "{result}" to the test output as "delete-protected-error.txt"14µs
And "{result}" should contain one of "retention, locked, immutable, protected"19µs
📎 Attachments:
write-user-identity.json
View JSON (3020 bytes)
{"UserName":"test-user-write","Provider":"gcp","Credentials":{"client_email":"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com","email":"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com","private_key_id":"862e25e3202690e27c62ce2bc4a7606b214eb924","project_id":"nodal-time-474015-p5","service_account_key":"{\n  \"type\": \"service_account\",\n  \"project_id\": \"nodal-time-474015-p5\",\n  \"private_key_id\": \"862e25e3202690e27c62ce2bc4a7606b214eb924\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDR9fPGFF4BImwW\\nD91YZOpE045Hevh1L8NWkiHjmGD+bu7BzUv41vq/86qkn5/yV3SLI89Stnwi9M01\\ncJ+oqdNNx/eJ51QS3LrSRQAi+Cfy6iFapVyw6w006IJnUP29tgah/wuYBhSPR1Wi\\no36m7+AT0BlgYS/9ai8hw7ZfevSWCUIOE4rTY9fCl1k4hMdYTdZz3/yxHqiTGQMn\\ndYjaIVE159KvMQP7aW8sMpbhdFLmFp5BLE96OAQ0V1Jq8qR+ij2cQt12fisWnTZm\\nrJHpprk/0T36lJdQdnb5+F6+DPqM8Ay636a8hnFPk54mKR92+EEn3Gs9XvAJDqsC\\n2I24CWTfAgMBAAECggEAGLT4mraK2VdToMT9Jwm5B6BdfcvasO+N7QIFOuMTht1G\\n+0dNSVsC5tOloPmnuLzR2g28t98BfJuSClfWceKKGv0NBA1Ut2OCGHxGJ9dL3Cnx\\nAtmyrp76Tt+NeNrvAQQKg8Wfd6Q/hxy91wWmQb64f5xdYBoPq6JzKWX+b/3oCj+V\\n943PwFDoCPP4I/EMp+Vph1gWPvs2Xu0qCdiK14PWQCbYzPewTDHJAmWuNmeITyHb\\n3X7RgK1BlaRbtLaEO2SiKCyjYivaWAyhUj/zwuYRc5fp/mEIM6xryrGmy/7dTU8T\\nRgwoentL8IMdnRq+X1qqUMvinsaiiYco0nZx4/p7AQKBgQD3pRYGj2tthx3T9y9H\\nBvPJaWAoI2RirC//CNqN5qRozraKBaj73sWUa0rgGCVYa94KosjyINHX0TZ9zigj\\nXvr0wzcM4RM2RdeoZahNBRDxVVR5szYgnfpM8RtJpdDF2FuYIBoeO838wIgpOEmv\\nRHei3jzvMAkp0gqhA4sM+d/VSwKBgQDZC2M/0CoQJUzewH9wnkup1EV8ryPJ0Hxe\\ntVufEL5PTtt57geXYq3F5qh9jinXu74NzD2wOILHYM52TZSQdl6AuLAUE1GUBab4\\nQ+VDvGy9gQPAWh+SsLz6h1rojwSpJdQrq8lMzAOpR1/3k9YHOztAbhB/8njI3Xc2\\n0raFLUl2PQKBgDiQO3SqI3Zz6ys0BVdqzhoN+ImSc+ZZv+i3o/vPV3Qc6vKhklRd\\nMLHSw9pliXolwSSaw90SA/wQbCrWALL7icSIJjXJ3vKBh12OQp+87X7B57aYaV+P\\n1dDnLT1oI0RdQ6Z+hpirPkRh0XfgxGvE7rKDolVbmmwz7nuSbJs9I5P7AoGARZE+\\n2J9SPCaYgvVUY7Z5LhAZzaMdZ3xpwLmEinGFbkoqUuSWjlFUvY/3BXdhtgI5IpcK\\nVsdmM521z3mCWuN12vBXj7e5eCZvpDeu7o0glYUavLamVBBOIkbsPopIxiaX4P+I\\n4BKsQb/c5K//9AVqMnaU103SpR9HLM1RL1Kar0kCgYEAufcFQiktxojyGouLo9pD\\nRgxpF1gk/pmDqdCFvQZL3eULvFJXsExhGCcFOtJB6/EKk5Z4JzaBhZY1JreTk/9E\\n3wKPIXQDAAo3Xd0VXBRrCfIyuU0kmBIPqRsUS6FcryoDspze4ZF/58IadasJz7Sq\\nc1YHLcnUFU575G7T4G4OrFA=\\n-----END PRIVATE KEY-----\\n\",\n  \"client_email\": \"test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"client_id\": \"114093962834554122395\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/test-user-write%40nodal-time-474015-p5.iam.gserviceaccount.com\",\n  \"universe_domain\": \"googleapis.com\"\n}\n","unique_id":"114093962834554122395"},"Policy":"{\"user\": \"test-user-write\", \"service\": \"projects/nodal-time-474015-p5/buckets/ccc-test-bucket-20260526t102300z\", \"level\": \"write\", \"role\": \"roles/editor\"}"}
Scenario: Service prevents object deletion by admin user during retention period @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"37µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"37µs
And I refer to "{result}" as "storage"26µs
And I call "{api}" with "GetServiceAPI" using argument "iam"32µs
And I refer to "{result}" as "iamService"23µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "admin-protected-object={Timestamp}.txt", and "compliance data"135ms
Then "{result}" is not an error25µs
When I call "{storage}" with "DeleteObject" using arguments "{ResourceName}" and "admin-protected-object={Timestamp}.txt"61ms
Then "{result}" is an error34µs
expected {result} to be an error, got
And I attach "{result}" to the test output as "admin-delete-protected-error.txt"23µs
Scenario: Service prevents object modification during retention period @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"43µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"44µs
And I refer to "{result}" as "storage"22µs
And I call "{api}" with "GetServiceAPI" using argument "iam"33µs
And I refer to "{result}" as "iamService"24µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-write", "{UID}", and "write"59µs
And I refer to "{result}" as "testUserWrite"30µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserWrite}", and "{true}"295ms
And "{result}" is not an error32µs
expected {result} to not be an error, but got: credentials not ready: credentials not ready for GCS access: googleapi: Error 403: test-user-write@nodal-time-474015-p5.iam.gserviceaccount.com does not have storage.buckets.list access to the Google Cloud project. Permission 'storage.buckets.list' denied on resource (or it may not exist)., forbidden
And I refer to "{result}" as "userStorage"17µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "modify-test-object={Timestamp}.txt", and "original content"21µs
Then "{result}" is not an error16µs
And I attach "{result}" to the test output as "original-object.json"22µs
When I call "{userStorage}" with "CreateObject" using arguments "{ResourceName}", "modify-test-object={Timestamp}.txt", and "modified content"19µs
Then "{result}" is an error17µs
And I attach "{result}" to the test output as "modify-protected-error.txt"16µs
And "{result}" should contain one of "retention, locked, immutable, protected, exists"23µs
Scenario: Service allows object read access during retention period @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Behavioural
Given a cloud api for "{Instance}" in "api"50µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"46µs
And I refer to "{result}" as "storage"29µs
And I call "{api}" with "GetServiceAPI" using argument "iam"23µs
And I refer to "{result}" as "iamService"17µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "readable-protected-object={Timestamp}.txt", and "readable data"135ms
Then "{result}" is not an error25µs
Given I call "{iamService}" with "ProvisionUserWithAccess" using arguments "test-user-read", "{UID}", and "read"142ms
And I refer to "{result}" as "testUserRead"27µs
And I attach "{result}" to the test output as "read-user-identity.json"33µs
And I call "{api}" with "GetServiceAPIWithIdentity" using arguments "object-storage", "{testUserRead}", and "{true}"73µs
And "{result}" is not an error59µs
expected {result} to not be an error, but got: Error calling {api}.GetServiceAPIWithIdentity: reflect: Call using *fmt.wrapError as type *iam.Identity
And I refer to "{result}" as "userStorage"16µs
When I call "{userStorage}" with "ReadObject" using arguments "{ResourceName}" and "readable-protected-object={Timestamp}.txt"18µs
Then "{result}" is not an error18µs
And I refer to "{result}" as "readResult"12µs
And I attach "{result}" to the test output as "read-protected-object.json"16µs
And "{readResult.Name}" is "readable-protected-object={Timestamp}.txt"22µs
📎 Attachments:
read-user-identity.json
View Content (227 bytes)
failed to create service account test-user-read: rpc error: code = ResourceExhausted desc = A quota has been reached for project number 784623368087: Service accounts created per minute per project.
error details: retry in 1m0s
Scenario: Test policy for object retention enforcement @PerService @object-storage @CCC.ObjStor @tlp-clear @tlp-green @tlp-amber @tlp-red @CCC.ObjStor.CN04 @Policy
Given a cloud api for "{Instance}" in "api"36µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"39µs
And I refer to "{result}" as "storage"32µs
And I call "{api}" with "GetServiceAPI" using argument "iam"22µs
And I refer to "{result}" as "iamService"17µs
When I attempt policy check "object-retention-enforcement" for control "CCC.ObjStor.CN04" assessment requirement "AR02" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"874ms
policy check failed: GCP Cloud Storage Object Retention Enforcement Check: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true18µs
📎 Attachments:
policy-result-object-retention-enforcement.json
View JSON (1395 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN04/AR02/object-retention-enforcement/gcp.yaml",
  "name": "GCP Cloud Storage Object Retention Enforcement Check",
  "service_type": "object-storage",
  "requirement_text": "The service MUST prevent deletion or modification of objects under active retention, maintaining data integrity and compliance requirements.\n",
  "validity_score": 9,
  "validity_commentary": "This query validates that a retention policy is configured and locked on the GCP bucket, preventing deletion or modification of any object before its retention period has elapsed. Strengths: - Locked policy cannot be shortened, removed, or overridden - Directly queries the retention policy lock status - Consistent with GCP compliance best practices Limitations: - Retention period is specified in seconds in GCP\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=\"json(retentionPolicy)\"\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN05.AR01 - Versioning with Unique Identifiers
Scenario: Service enables versioning and objects receive unique version identifiers @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural
Given a cloud api for "{Instance}" in "api"46µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"40µs
And I refer to "{result}" as "storage"18µs
When I call "{storage}" with "IsBucketVersioningEnabled" using argument "{ResourceName}"18µs
Then "{result}" is true19µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "versioned-object.txt", and "test content"129ms
And I refer to "{result}" as "createdObject"22µs
Then "{createdObject.VersionID}" is not empty26µs
And I attach "{result}" to the test output as "versioned-object.json"18µs
Scenario: Objects are stored with unique version identifiers @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy
Given a cloud api for "{Instance}" in "api"39µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"40µs
And I refer to "{result}" as "storage"18µs
When I attempt policy check "object-storage-versioning" for control "CCC.ObjStor.CN05" assessment requirement "AR01" for service "{ServiceType}" on resource "{ResourceName}" and provider "{Provider}"865ms
policy check failed: GCP Cloud Storage Bucket Versioning Configuration: login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.
Then "{result}" is true30µs
📎 Attachments:
policy-result-object-storage-versioning.json
View JSON (1345 bytes)
{
  "policy_path": "/home/runner/work/ccc-cfi-compliance/ccc-cfi-compliance/testing/policy/CCC.ObjStor/CCC.ObjStor.CN05/AR01/object-storage-versioning/gcp.yaml",
  "name": "GCP Cloud Storage Bucket Versioning Configuration",
  "service_type": "object-storage",
  "requirement_text": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.\n",
  "validity_score": 9,
  "validity_commentary": "This query validates that GCP Cloud Storage bucket versioning is enabled. When versioning is enabled, each object version gets a unique generation number. Strengths: - Directly queries versioning configuration - GCS automatically assigns unique generation numbers - Versioning can be suspended but history is preserved Limitations: - Does not validate lifecycle rules that may delete versions - Suspended versioning stops creating new versions\n",
  "query_template": "gcloud storage buckets describe gs://${ResourceName} \\\n  --format=json\n",
  "query_executed": "gcloud storage buckets describe gs://ccc-test-bucket-20260526t102300z \\\n  --format=json\n",
  "query_output": "",
  "query_error": "login: gcloud auth activate-service-account: exit status 1: ERROR: (gcloud.auth.activate-service-account) The .json key file is not in a valid format.\n",
  "passed": false,
  "rule_results": null
}
Feature: CCC.ObjStor.CN05.AR02 - New Version ID on Modification
Scenario: Modified objects receive new version identifiers @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural
Given a cloud api for "{Instance}" in "api"51µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"55µs
And I refer to "{result}" as "storage"37µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "original content"134ms
And I refer to "{result.VersionID}" as "version1"30µs
And I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "modified content"140ms
And I refer to "{result.VersionID}" as "version2"24µs
Then "{version1}" is not equal to "{version2}"23µs
Scenario: Modified objects receive new version identifiers @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @Duplicate
Given a cloud api for "{Instance}" in "api"37µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"30µs
And I refer to "{result}" as "storage"27µs
Then no-op required25µs
Feature: CCC.ObjStor.CN05.AR03 - Recovery of Previous Versions
Scenario: Modified objects receive new version identifiers @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural
Given a cloud api for "{Instance}" in "api"31µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"37µs
And I refer to "{result}" as "storage"26µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "original content"135ms
And I refer to "{result.VersionID}" as "version1"31µs
And I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "modified content"133ms
And I refer to "{result.VersionID}" as "version2"29µs
And I call "{storage}" with "ReadObjectAtVersion" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "{version1}"96ms
And I attach "{result}" to the test output as "original-content.json"54µs
Then "{result.Data}" contains "original content"46µs
When I call "{storage}" with "ReadObjectAtVersion" using arguments "{ResourceName}", "version-test-object={Timestamp}.txt", and "{version2}"93ms
Then "{result.Data}" contains "modified content"33µs
And I attach "{result}" to the test output as "modified-content.json"43µs
📎 Attachments:
original-content.json
View JSON (233 bytes)
{"ID":"version-test-object=1779791146460.txt","BucketID":"ccc-test-bucket-20260526t102300z","Name":"version-test-object=1779791146460.txt","Size":16,"Data":["original content"],"Encryption":"","EncryptionAlgorithm":"","VersionID":""}
modified-content.json
View JSON (233 bytes)
{"ID":"version-test-object=1779791146460.txt","BucketID":"ccc-test-bucket-20260526t102300z","Name":"version-test-object=1779791146460.txt","Size":16,"Data":["modified content"],"Encryption":"","EncryptionAlgorithm":"","VersionID":""}
Scenario: Previous object versions can be recovered @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy
Given a cloud api for "{Instance}" in "api"47µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"56µs
And I refer to "{result}" as "storage"21µs
Then no-op required19µs
Feature: CCC.ObjStor.CN05.AR04 - Retain Versions on Delete
Scenario: Deleted object data can be reloaded from previous version @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural
Given a cloud api for "{Instance}" in "api"46µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"48µs
And I refer to "{result}" as "storage"25µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "recover-deleted-object={Timestamp}.txt", and "data to retain"135ms
And I refer to "{result.VersionID}" as "retainedVersionId"33µs
When I call "{storage}" with "DeleteObject" using arguments "{ResourceName}" and "recover-deleted-object={Timestamp}.txt"65ms
When I call "{storage}" with "ReadObjectAtVersion" using arguments "{ResourceName}", "recover-deleted-object={Timestamp}.txt", and "{retainedVersionId}"100ms
Then "{result.Data}" contains "data to retain"37µs
And I attach "{result}" to the test output as "recovered-deleted-version.json"41µs
📎 Attachments:
recovered-deleted-version.json
View JSON (237 bytes)
{"ID":"recover-deleted-object=1779791146919.txt","BucketID":"ccc-test-bucket-20260526t102300z","Name":"recover-deleted-object=1779791146919.txt","Size":14,"Data":["data to retain"],"Encryption":"","EncryptionAlgorithm":"","VersionID":""}
Scenario: Deleted object version remains in version list @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Behavioural
Given a cloud api for "{Instance}" in "api"43µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"44µs
And I refer to "{result}" as "storage"28µs
When I call "{storage}" with "CreateObject" using arguments "{ResourceName}", "list-deleted-versions-object={Timestamp}.txt", and "versioned data"109ms
And I refer to "{result.VersionID}" as "listedVersionId"28µs
When I call "{storage}" with "DeleteObject" using arguments "{ResourceName}" and "list-deleted-versions-object={Timestamp}.txt"64ms
When I call "{storage}" with "ListObjectVersions" using arguments "{ResourceName}" and "list-deleted-versions-object={Timestamp}.txt"36µs
And "{result}" is an array of objects with at least the following contents22µs
VersionIDObjectID
{listedVersionId}list-deleted-versions-object={Timestamp}.txt
field {result} is not an array
And I attach "{result}" to the test output as "versions-after-delete.json"21µs
Scenario: Object versions are retained after deletion @PerService @object-storage @CCC.ObjStor @CCC.ObjStor.CN05 @tlp-clear @tlp-green @tlp-amber @tlp-red @Policy @Duplicate
Given a cloud api for "{Instance}" in "api"49µs
And I call "{api}" with "GetServiceAPI" using argument "object-storage"45µs
And I refer to "{result}" as "storage"27µs
Then no-op required27µs