# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# E2E Test: Data Factory/LinkedService_InlineSecrets_Audit
# Real Azure Policy: "Azure Data Factory linked services should use Key Vault for storing secrets"
# Source: regolator/policyDefinitions/Data Factory/LinkedService_InlineSecrets_Audit.json
#
# Features exercised:
#   - Large anyOf with 20+ branches
#   - "contains" operator for secret keywords in connectionString
#   - "exists" checks for secret fields
#   - "equals" / "notEquals" / "in" checks for .type field (SecureString vs AzureKeyVaultSecret)
#   - Service-type-prefixed aliases (SqlServer., AzureStorage., etc.)

aliases: test_aliases.json

policy_definition: |
  {
    "properties": {
      "displayName": "Azure Data Factory linked services should use Key Vault for storing secrets",
      "policyType": "BuiltIn",
      "mode": "All",
      "parameters": {
        "effect": {
          "type": "String",
          "allowedValues": ["Audit", "Deny", "Disabled"],
          "defaultValue": "Audit"
        }
      },
      "policyRule": {
        "if": {
          "allOf": [
            {
              "field": "type",
              "equals": "Microsoft.DataFactory/factories/linkedservices"
            },
            {
              "anyOf": [
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                      "exists": "true"
                    },
                    {
                      "anyOf": [
                        {
                          "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                          "contains": "AccountKey="
                        },
                        {
                          "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                          "contains": "PWD="
                        },
                        {
                          "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                          "contains": "Password="
                        },
                        {
                          "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                          "contains": "CredString="
                        },
                        {
                          "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
                          "contains": "pwd="
                        }
                      ]
                    }
                  ]
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password.type",
                  "equals": "SecureString"
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password.type",
                      "exists": "false"
                    }
                  ]
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/AzureSqlDW.typeProperties.servicePrincipalKey.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/AzureSearch.typeProperties.key.type",
                  "equals": "SecureString"
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.sasUri",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.sasUri.type",
                      "notEquals": "AzureKeyVaultSecret"
                    }
                  ]
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/AzureBlobStorage.typeProperties.servicePrincipalKey",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/AzureBlobStorage.typeProperties.servicePrincipalKey.type",
                      "notEquals": "AzureKeyVaultSecret"
                    }
                  ]
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.accountKey",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/CosmosDb.typeProperties.accountKey.type",
                      "notEquals": "AzureKeyVaultSecret"
                    }
                  ]
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.encryptedCredential",
                  "exists": "true"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/AmazonMWS.typeProperties.mwsAuthToken.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/AmazonMWS.typeProperties.secretKey.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/AmazonS3.typeProperties.secretAccessKey.type",
                  "equals": "SecureString"
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/Dynamics.typeProperties.servicePrincipalCredential",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/Dynamics.typeProperties.servicePrincipalCredential.type",
                      "equals": "SecureString"
                    }
                  ]
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/Hubspot.typeProperties.accessToken",
                      "exists": "true"
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/Hubspot.typeProperties.accessToken.type",
                      "equals": "SecureString"
                    }
                  ]
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/Odbc.typeProperties.credential.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/GoogleAdWords.typeProperties.developerToken.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/GoogleBigQuery.typeProperties.clientSecret.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/GoogleBigQuery.typeProperties.refreshToken.type",
                  "equals": "SecureString"
                },
                {
                  "allOf": [
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/type",
                      "in": [
                        "MongoDbAtlas",
                        "MongoDbV2"
                      ]
                    },
                    {
                      "field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString.type",
                      "notEquals": "AzureKeyVaultSecret"
                    }
                  ]
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/OData.typeProperties.servicePrincipalEmbeddedCert.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/OData.typeProperties.servicePrincipalEmbeddedCertPassword.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/Sftp.typeProperties.privateKeyContent.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/Sftp.typeProperties.passPhrase.type",
                  "equals": "SecureString"
                },
                {
                  "field": "Microsoft.DataFactory/factories/linkedservices/Salesforce.typeProperties.securityToken.type",
                  "equals": "SecureString"
                }
              ]
            }
          ]
        },
        "then": {
          "effect": "[parameters('effect')]"
        }
      }
    }
  }

cases:
  # =========================================================================
  # connectionString contains "Password=" → Audit
  # =========================================================================

  - note: audit_connection_string_with_password
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sql-inline-password"
      properties:
        type: SqlServer
        typeProperties:
          connectionString: "Server=myserver.database.windows.net;Database=mydb;User ID=admin;Password=secret123"
    want_effect: "Audit"

  # =========================================================================
  # connectionString without secret keywords → pass
  # =========================================================================

  - note: pass_connection_string_no_secrets
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sql-integrated"
      properties:
        type: SqlServer
        typeProperties:
          connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
    want_undefined: true

  # =========================================================================
  # SqlServer password.type = SecureString → Audit
  # =========================================================================

  - note: audit_sql_server_secure_string
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sql-securestring"
      properties:
        type: SqlServer
        typeProperties:
          connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
          password:
            type: SecureString
            value: "my-password"
    want_effect: "Audit"

  # =========================================================================
  # SqlServer password.type = AzureKeyVaultSecret → pass
  # =========================================================================

  - note: pass_sql_server_keyvault
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sql-keyvault"
      properties:
        type: SqlServer
        typeProperties:
          connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
          password:
            type: AzureKeyVaultSecret
            store:
              referenceName: myKeyVault
              type: LinkedServiceReference
            secretName: mySecret
    want_undefined: true

  # =========================================================================
  # encryptedCredential exists → Audit
  # =========================================================================

  - note: audit_encrypted_credential
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-encrypted"
      properties:
        type: AzureBlobStorage
        typeProperties:
          connectionString: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net"
          encryptedCredential: "eyJWZXJzaW9uIj..."
    want_effect: "Audit"

  # =========================================================================
  # No secrets at all → pass
  # =========================================================================

  - note: pass_no_secrets
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-clean"
      properties:
        type: AzureBlobFS
        typeProperties:
          url: "https://mydatalake.dfs.core.windows.net"
    want_undefined: true

  # =========================================================================
  # Wrong resource type → pass
  # =========================================================================

  - note: pass_wrong_type
    resource:
      type: "Microsoft.Storage/storageAccounts"
      name: "not-data-factory"
      properties:
        supportsHttpsTrafficOnly: true
    want_undefined: true

  # =========================================================================
  # AzureStorage sasUri exists but type not AzureKeyVaultSecret → Audit
  # =========================================================================

  - note: audit_storage_sas_no_keyvault
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-storage-inline-sas"
      properties:
        type: AzureStorage
        typeProperties:
          sasUri: "https://mystorage.blob.core.windows.net/?sv=2020-08-04&ss=b&srt=sco&sp=rwdlacupx"
    want_effect: "Audit"

  # =========================================================================
  # AzureSqlDW servicePrincipalKey.type = SecureString → Audit
  # =========================================================================

  - note: audit_azure_sql_dw_spkey_securestring
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sqldw-spkey"
      properties:
        type: AzureSqlDW
        typeProperties:
          connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
          servicePrincipalKey:
            type: SecureString
            value: "my-sp-key"
    want_effect: "Audit"

  # =========================================================================
  # AzureStorage accountKey exists + type != AzureKeyVaultSecret → Audit
  # =========================================================================

  - note: audit_storage_accountkey_not_keyvault
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-storage-accountkey"
      properties:
        type: AzureStorage
        typeProperties:
          connectionString: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net"
          accountKey:
            type: SecureString
            value: "base64accountkey=="
    want_effect: "Audit"

  # =========================================================================
  # MongoDbAtlas connectionString.type != AzureKeyVaultSecret → Audit
  # =========================================================================

  - note: audit_mongodbatlas_connstr_not_keyvault
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-mongodbatlas-inline"
      properties:
        type: MongoDbAtlas
        typeProperties:
          connectionString:
            type: SecureString
            value: "mongodb+srv://user:pass@cluster0.mongodb.net/mydb"
          database: mydb
    want_effect: "Audit"

  # =========================================================================
  # AmazonS3 secretAccessKey.type = SecureString → Audit
  # =========================================================================

  - note: audit_amazon_s3_secret_securestring
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-amazons3-secret"
      properties:
        type: AmazonS3
        typeProperties:
          accessKeyId: "AKIAIOSFODNN7EXAMPLE"
          secretAccessKey:
            type: SecureString
            value: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    want_effect: "Audit"

  # =========================================================================
  # Sftp privateKeyContent.type = SecureString → Audit
  # =========================================================================

  - note: audit_sftp_privatekey_securestring
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-sftp-privatekey"
      properties:
        type: Sftp
        typeProperties:
          host: "sftp.example.com"
          userName: "sftpuser"
          privateKeyContent:
            type: SecureString
            value: "-----BEGIN RSA PRIVATE KEY-----..."
    want_effect: "Audit"

  # =========================================================================
  # Odbc credential.type = AzureKeyVaultSecret → pass (not SecureString)
  # =========================================================================

  - note: pass_odbc_credential_keyvault
    resource:
      type: "Microsoft.DataFactory/factories/linkedservices"
      name: "adf-odbc-keyvault"
      properties:
        type: Odbc
        typeProperties:
          connectionString: "Driver={SQL Server};Server=myserver;Database=mydb"
          credential:
            type: AzureKeyVaultSecret
            store:
              referenceName: myKeyVault
              type: LinkedServiceReference
            secretName: odbcCredential
    want_undefined: true
