uqa-sql 0.4.0

PostgreSQL-compatible SQL compiler built on libpg_query
Documentation
//
// Unified Query Algebra
//
// Copyright (c) 2023-2026 Cognica, Inc.
//

use super::*;
use crate::catalog::{
    roles::RoleDefinition,
    security::{
        columns::grant_column_acl,
        table::{grant_acl, TableAclPrivilege, TablePrivilegeCheck},
    },
    VirtualRelation,
};

#[test]
fn system_acl_masks_relation_writes_but_preserves_attribute_grants_and_grant_options() {
    let relation = SystemRelation::Projected(VirtualRelation::PgClass);
    let mut reader = RoleDefinition::bootstrap();
    reader.name = "reader".into();
    reader.oid = 20_001;
    reader.object_id = [1; 16];
    reader.attributes.clear();
    let roles = BTreeMap::from([
        ("uqa".into(), RoleDefinition::bootstrap()),
        ("reader".into(), reader),
    ]);
    let mut security = relation.bootstrap_security().resolve(&roles).unwrap();
    let memberships = BTreeMap::new();
    for privilege in TableAclPrivilege::ALL {
        grant_acl(&mut security, privilege, &["reader".into()], "uqa", true);
        let check = TablePrivilegeCheck {
            privilege,
            grant_option: false,
        };
        let expected = !matches!(
            privilege,
            TableAclPrivilege::Insert
                | TableAclPrivilege::Update
                | TableAclPrivilege::Delete
                | TableAclPrivilege::Truncate
        );
        assert_eq!(
            has_table_privilege(relation, &security, "reader", check, &roles, &memberships),
            expected,
            "{privilege:?}"
        );
        assert!(has_table_privilege(
            relation,
            &security,
            "reader",
            TablePrivilegeCheck {
                grant_option: true,
                ..check
            },
            &roles,
            &memberships
        ));
        assert!(has_table_privilege(
            relation,
            &security,
            "uqa",
            check,
            &roles,
            &memberships
        ));
    }
    grant_column_acl(
        &mut security,
        "relname",
        TableAclPrivilege::Update,
        &["reader".into()],
        "uqa",
        false,
    );
    let check = TablePrivilegeCheck {
        privilege: TableAclPrivilege::Update,
        grant_option: false,
    };
    assert!(has_column_privilege(
        relation,
        &security,
        "relname",
        "reader",
        check,
        &roles,
        &memberships
    ));
    assert!(!has_column_privilege(
        relation,
        &security,
        "relnamespace",
        "reader",
        check,
        &roles,
        &memberships
    ));
    let settings = SystemRelation::Projected(VirtualRelation::PgSettings);
    assert!(has_table_privilege(
        settings,
        &settings.bootstrap_security().resolve(&roles).unwrap(),
        "reader",
        check,
        &roles,
        &memberships
    ));
}

#[test]
fn system_acl_validation_rejects_orphan_roles_wrong_owners_and_missing_columns() {
    let relation = SystemRelation::Projected(crate::catalog::VirtualRelation::PgAuthid);
    let roles = BTreeMap::from([("uqa".into(), RoleDefinition::bootstrap())]);
    let baseline = relation.bootstrap_security().resolve(&roles).unwrap();
    validate_security(relation, &baseline, &roles).unwrap();
    let mut invalid = baseline.clone();
    invalid.role_owner = "missing".into();
    assert!(validate_security(relation, &invalid, &roles).is_err());
    let mut invalid = baseline.clone();
    grant_acl(
        &mut invalid,
        TableAclPrivilege::Select,
        &["missing".into()],
        "uqa",
        false,
    );
    assert!(validate_security(relation, &invalid, &roles).is_err());
    let mut invalid = baseline;
    grant_column_acl(
        &mut invalid,
        "absent",
        TableAclPrivilege::Select,
        &[uqa_core::catalog_acl::AclGrantee::Public],
        "uqa",
        false,
    );
    assert!(validate_security(relation, &invalid, &roles).is_err());
}

#[test]
fn system_defaults_follow_bootstrap_identity_after_rename_and_name_reuse() {
    let mut bootstrap = RoleDefinition::bootstrap();
    bootstrap.name = "renamed_bootstrap".into();
    let mut replacement = RoleDefinition::bootstrap();
    replacement.oid = 20_001;
    replacement.object_id = [1; 16];
    replacement.attributes.clear();
    let roles = BTreeMap::from([
        (bootstrap.name.clone(), bootstrap),
        (replacement.name.clone(), replacement),
    ]);
    let relation = SystemRelation::Projected(crate::catalog::VirtualRelation::PgAuthid);
    let bound = relation.bootstrap_security();
    let named = bound.resolve(&roles).unwrap();
    assert_eq!(named.role_owner, "renamed_bootstrap");
    validate_security(relation, &named, &roles).unwrap();
    let check = TablePrivilegeCheck {
        privilege: TableAclPrivilege::Select,
        grant_option: false,
    };
    assert!(has_table_privilege(
        relation,
        &named,
        "renamed_bootstrap",
        check,
        &roles,
        &BTreeMap::new()
    ));
    assert!(!has_table_privilege(
        relation,
        &named,
        "uqa",
        check,
        &roles,
        &BTreeMap::new()
    ));
}