> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/database-devops/3.0/use-db-devops/governance-and-compliance/using-opa-with-database-devops.md).

# Using Rego for Database DevOps Steps

This guide explains how to use **Harness Policy Agent** to enforce policies on **DataBase Devops** steps. Rego is a declarative policy language used by Open Policy Agent (OPA) for policy-based control.

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* **Rego knowledge:** Basic understanding of the Rego policy language and OPA is recommended.

### Write a Rego policy for Database DevOps steps <a href="#write-a-rego-policy-for-database-devops-steps" id="write-a-rego-policy-for-database-devops-steps"></a>

A Rego policy can validate that changesets conform to specific rules, such as enforcing naming conventions or restricting certain SQL operations.

#### Example policy: restrict DROP TABLE <a href="#example-policy-restrict-drop-table" id="example-policy-restrict-drop-table"></a>

Go to DB Governance section and create a new policy

```rego
package db_sql
policies := [
{
        "error_message": "Dropping of table is not allowed.",
        "rules": [
            {
                "types": [
                    "jdbc:sqlserver","jdbc:mysql","jdbc:postgresql","jdbc:oracle:thin"
                ],
                "regex": [
                    "drop"
                ]
            }
        ]
}
]
deny[msg] {
    some i,j,k,l
    policy := policies[i];
    type := input.dbInstance.type;
    rule := policy.rules[j];
    type = rule.types[_];
    regex.match(lower(concat("",[".*",rule.regex[k],".*"])),lower(input.sqlStatements[l]));
    msg := concat("",["Policy violation:\n The following sql statement:\n",input.sqlStatements[l],"\n\n Matches the following regex: \n",rule.regex[k]])
}
```

![Rego Policy Flow](/files/FJlphqybpYVURXJxVchp)

#### Sample payload <a href="#sample-payload" id="sample-payload"></a>

You can test the policy on sample payloads

```json
{
  "dbInstance": {
    "dbConnectionUrl": "jdbc:sqlserver://35.xxx.125.32:1433;trustServerCertificate=true;databaseName=db_oajzu",
    "identifier": "enkkMcacHU",
    "name": "enkkMcacHU",
    "tags": {
      "tag1": "val1",
      "tag2": "val2"
    },
    "type": "jdbc:sqlserver"
  },
  "dbSchema": {
    "identifier": "CTJPjhVwkU",
    "name": "CTJPjhVwkU"
  },
  "sqlStatements": [
    "DROP TABLE public;"
  ]
}
```

#### Create a custom policy set and attach the policy <a href="#create-a-custom-policy-set-and-attach-the-policy" id="create-a-custom-policy-set-and-attach-the-policy"></a>

![Rego Policy Flow](/files/Y1kwHXSEo3cvBwnHdIFi))

#### Attach the policy set in Database DevOps step configuration <a href="#attach-the-policy-set-in-database-devops-step-configuration" id="attach-the-policy-set-in-database-devops-step-configuration"></a>

![Add evaluation](/files/LxA3TsBCiCun2bfYde8f)

### Validate Liquibase steps with OPA <a href="#validate-liquibase-steps-with-opa" id="validate-liquibase-steps-with-opa"></a>

Run the OPA policy check against the changeset during pipeline run:

If a violation occurs, OPA will output a message indicating the problem (e.g., "Dropping tables is not allowed: users") and result in error / warning as per configuration.

![failed pipeline](/files/g2ci20bMI6hR4oZvx6Al)

### OPA policy examples <a href="#opa-policy-examples" id="opa-policy-examples"></a>

#### Table name limit <a href="#table-name-limit" id="table-name-limit"></a>

The function checks if any of the SQL statements in the input create a table with a name longer than 10 characters. If a match is found, it means that the table name violates the rule and the function returns a message indicating the violation.

```rego
package db_sql

deny[msg] {
    some l
    sql := lower(input.sqlStatements[l])
    
    # Extract table name, handling optional schema (e.g., "public.")
    matches := regex.find_n(`(?i)create\s+table\s+([a-zA-Z0-9_]+\.)?([a-zA-Z0-9_]+)`, sql, -1)

    some j
    table_name := matches[j]  # Extract match

    # If the table has a schema prefix, extract just the table name part
    parts := split(table_name, ".")
    actual_table_name := parts[count(parts) - 1]

    count(actual_table_name) > 10

    msg := sprintf("Table name '%s' exceeds 10 characters, which is not permitted", [actual_table_name])
}
```

#### Schema name limit <a href="#schema-name-limit" id="schema-name-limit"></a>

The existing code already has a schema name length check in the "Prevent Data Drop" section, but it could be formalized as a separate policy:

```rego
package db_sql

deny[msg] {
    some l
    sql := lower(input.sqlStatements[l])
    
    # Extract schema name
    matches := regex.find_n(`(?i)create\s+schema\s+([a-zA-Z0-9_]+)`, sql, -1)
    
    some j
    schema_name := matches[j]
    
    count(schema_name) > 30
    
    msg := sprintf("Schema name '%s' exceeds 30 characters, which is not permitted", [schema_name])
}
```

#### Prevent direct system table access <a href="#prevent-direct-system-table-access" id="prevent-direct-system-table-access"></a>

This policy checks if any SQL statement attempts to access system tables (e.g., those starting with "sys." in SQL Server). If such access is detected, it returns a violation message.

```rego
package db_sql

deny[msg] {
    some l
    sql := lower(input.sqlStatements[l])
    
    system_tables := [
        "sys\\.", "information_schema\\.", "pg_catalog\\.",
        "sysobjects", "syscolumns", "sysusers"
    ]
    
    some i
    regex.match(concat("", [".*select.*from.*", system_tables[i], ".*"]), sql)
    
    msg := sprintf("Direct access to system tables is not permitted: %s", [sql])
}
```

#### Prevent large transactions <a href="#prevent-large-transactions" id="prevent-large-transactions"></a>

```rego
package db_sql

deny[msg] {
    count(input.sqlStatements) > 50
    
    msg := "Transaction contains too many statements. Please break it into smaller transactions."
}
```

#### DB policy populator <a href="#db-policy-populator" id="db-policy-populator"></a>

The types represent the different types of databases (e.g., sybase, oracle, mssql). The regular expressions represent the SQL statements that are not allowed in each type of database. if a match is found, it means that the SQL statement violates a policy and the function returns a message indicating the violation.

```rego
package db_sql

policies := [
    {
        "error_message": "Switching to system databases is not allowed.",
        "rules": [
            {
                "types": [
                    "sybase"
                ],
                "regex": [
                    "use\\s+master",
                    "use\\s+GDMGAdmin",
                    "use\\s+GDMGSecurity",
                    "use\\s+sybsecurity",
                    "use\\s+sybsystemprocs",
                    "use\\s+SEMSAuditDb"
                ]
            }
        ]
    },
    {
        "error_message": "Creating or dropping users and roles via DDL is not allowed.",
        "rules": [
            {
                "types": [
                    "sybase"
                ],
                "regex": [
                    "sp_addlogin",
                    "sp_adduser",
                    "sp_addalias",
                    "sp_dropuser",
                    "sp_dropalias",
                    "sp_droplogin",
                    "sp_locklogin",
                    "sp_addgroup",
                    "sp_modifylogin",
                    "sp_changegroup",
                    "sp_addrole",
                    "sp_addrolemember",
                    "sp_droprole",
                    "create\\s+role",
                    "create\\s+database"
                ]
            },
            {
                "types": [
                    "oracle"
                ],
                "regex": [
                    "create\\s+user",
                    "drop\\s+user",
                    "alter\\s+user",
                    "create\\s+role",
                    "drop\\s+role"
                ]
            },
            {
                "types": [
                    "mssql"
                ],
                "regex": [
                    "sp_addlogin",
                    "sp_sec_addlogin",
                    "sp_sec_addnotification",
                    "sp_sec_denylogin",
                    "sp_sec_grantlogin",
                    "sp_sec_revokelogin",
                    "sp_sec_returnaccess",
                    "sp_sec_setuppswdproperty",
                    "sp_adduser",
                    "sp_dropuser",
                    "sp_addrole",
                    "sp_addrolemember",
                    "sp_droprole",
                    "sp_droplogin",
                    "sp_sec_modifylogin",
                    "create\\s+role",
                    "sp_changegroup"
                ]
            }
        ]
    },
    {
        "error_message": "Granting or revoking permissions to public roles is not allowed.",
        "rules": [
            {
                "types": [
                    "mssql","oracle","sybase"
                ],
                "regex": [
                    "grant.*to\\s+public",
                    "revoke.*from\\s+public"
                ]
            }
        ]
    },
    {
        "error_message": "Use of certain system stored procedures is not allowed.",
        "rules": [
            {
                "types": [
                    "mssql"
                ],
                "regex": [
                    "sp_password_sec",
                    "xp_cmdshell",
                    "xp_regwrite",
                    "sp_denylogin",
                    "sp_revokelogin",
                    "sp_addlogin_sec",
                    "sp_grantlogin",
                    "sp_changedbowner",
                    "sp_changeobjectowner",
                    "sp_addapprole",
                    "sp_dropapprole",
                    "sp_grantdboaccess",
                    "sp_addsrvrolemember"
                ]
            }
        ]
    },
    {
        "error_message": "Modifying profiles, schemas, tablespaces, databases, and systems are not allowed.",
        "rules": [
            {
                "types": [
                    "oracle"
                ],
                "regex": [
                    "create\\s+(profile|schema|tablespace|system)\\s+[^\\.]+",
                    "alter\\s+(tablespace|system)\\s+[^\\.]+"
                ]
            },
            {
                "types": [
                    "mssql","sybase"
                ],
                "regex": [
                    "create\\s+(database)\\s+[^\\.]+"
                ]
            }
        ]
    }
]

deny[msg] {
    some i
    policy := policies[i];
    type := input.db_instances[_].db_type;
    some j
    rule := policy.rules[j];
    type = rule.types[_];
    some k
    some l
    regex.match(concat("",[".*",rule.regex[k],".*"]),lower(input.sql_statements[l].sql));
    msg := concat("",["Policy violation:\n The following sql statement:\n",input.sql_statements[l].sql,"\n\n Matches the following regex: \n",rule.regex[k]])
  }
```

### Next steps <a href="#next-steps" id="next-steps"></a>

* Go to [Approval gates](/database-devops/use-db-devops/governance-and-compliance/using-approval-gates-with-harness-ui.md) to require human review before applying database changes.
* Go to [Audit trails](/database-devops/use-db-devops/governance-and-compliance/audit-trails.md) to track all Database DevOps events for compliance.
