Skip to content

quack: pin SQL NULL operands over existing sql_where (tests + PostgreSQL differential) #420

quack: pin SQL NULL operands over existing sql_where (tests + PostgreSQL differential)

quack: pin SQL NULL operands over existing sql_where (tests + PostgreSQL differential) #420

Workflow file for this run

name: Identity
# Two jobs for two different contracts, kept apart on purpose:
#
# exchange-fidelity lance-graph-dir-sim simulates hybrid Exchange. Its
# behaviour follows what Exchange and AD actually do:
# recipient types, routing addresses, proxy addresses,
# joins on the object GUID.
# iam-immutability lance-graph-rbac authorizes on an immutable principal.
# Delegation (RFC 8693 `act`) names who acts, never
# whose authority is used.
#
# The simulator must not take on IAM's rules (an address is not an identity
# there; it is an Exchange attribute with Exchange's lifecycle), and IAM must
# not take on the simulator's (an address never decides who a principal is).
#
# Each job runs its whole crate, then checks that the tests pinning the
# contract still exist by name. A renamed or deleted pinning test fails the
# job instead of silently dropping out of the run.
on:
push:
branches:
- main
pull_request:
paths:
- crates/lance-graph-dir-sim/**
- crates/lance-graph-rbac/**
- crates/lance-graph-contract/**
- crates/lance-graph-quack/**
- crates/lance-graph-mask-risc/**
- .github/workflows/identity.yml
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
CARGO_PROFILE_DEV_DEBUG: "0"
RUST_BACKTRACE: "1"
jobs:
exchange-fidelity:
name: Exchange dir-sim fidelity
runs-on: ubuntu-24.04
timeout-minutes: 30
defaults:
run:
working-directory: lance-graph
steps:
- uses: actions/checkout@v4
with:
path: lance-graph
persist-credentials: false
# lance-graph-dir-sim is workspace-excluded: it path-deps OGAR
# (ogar-dir-core / ogar-dir-sim / ogar-ad) and, through mask-risc,
# ndarray. Both are NO-PIN sibling checkouts, as in rust-test.yml.
- name: Checkout AdaWorldAPI/ndarray (sibling dependency)
uses: actions/checkout@v4
with:
repository: AdaWorldAPI/ndarray
path: ndarray
persist-credentials: false
- name: Checkout AdaWorldAPI/OGAR (sibling dependency)
uses: actions/checkout@v4
with:
repository: AdaWorldAPI/OGAR
path: OGAR
persist-credentials: false
- name: Setup rust toolchain (pinned by rust-toolchain.toml)
run: rustup show
# `.cargo/config.toml` builds with target-cpu=native, and cargo's
# fingerprint sees the flag text, not the CPU: an artifact built on a
# runner with AVX-512 would be reused on one without and die with
# SIGILL. Spell `native` out as this runner's exact feature list:
# a different CPU then gives different flags, cargo recompiles by itself,
# and the cache is keyed to the same flags.
- name: Resolve target-cpu=native for this runner
id: cpu
run: |
flags=$(.github/scripts/resolve-native-rustflags.sh)
echo "RUSTFLAGS=$flags" >> "$GITHUB_ENV"
hash=$(printf %s "$flags" | sha256sum | cut -c1-16)
echo "flags=$hash" >> "$GITHUB_OUTPUT"
echo "native is \`$(.github/scripts/resolve-native-rustflags.sh --cpu)\`, features $hash, job \`$GITHUB_JOB\`" >> "$GITHUB_STEP_SUMMARY"
- uses: Swatinem/rust-cache@v2
with:
key: cpu-${{ steps.cpu.outputs.flags }}
workspaces: lance-graph/crates/lance-graph-dir-sim
- name: Run the simulator's tests
run: cargo test --manifest-path crates/lance-graph-dir-sim/Cargo.toml
- name: Run the simulator's role tests (feature rbac)
# view_actors and membership_path need the rbac feature; without
# this step they compile only locally.
run: cargo test --manifest-path crates/lance-graph-dir-sim/Cargo.toml --features rbac
- name: The tests pinning Exchange behaviour exist
run: |
cargo test -q --manifest-path crates/lance-graph-dir-sim/Cargo.toml -- --list \
> "$RUNNER_TEMP/tests.txt"
missing=0
while read -r name; do
[ -z "$name" ] && continue
if ! grep -Fxq "$name: test" "$RUNNER_TEMP/tests.txt"; then
echo "::error::missing pinning test: $name"
missing=1
fi
done <<'EOF'
enabling_a_mailbox_stamps_its_routing_proxy
leftover_mail_addresses_of_a_non_recipient_claim_nothing_but_its_upn_does
a_group_does_not_collide_with_a_non_recipients_leftovers
an_introduced_routing_address_must_match_the_alias
the_routing_address_must_be_the_nodes_own_alias
the_routing_address_must_be_a_proxy
the_prefix_names_the_kind_and_the_case_of_smtp_marks_the_primary
from_ad_reads_the_triplet_and_strips_smtp
a_synchronized_user_is_mirrored_and_a_cloud_only_user_is_synthetic
a_mirrored_user_inside_the_synthetic_container_is_refused
an_unencoded_on_premises_dn_is_refused_not_made_synthetic
mailbox_records_are_not_observed_as_users
a_cloud_read_is_shown_mirrored_and_synthetic
a_simulated_version_marks_what_it_created
unsafe_values_are_base64_and_long_lines_fold
iam_filters_entries_and_attributes
writes_are_refused_and_the_directory_does_not_change
the_root_dse_is_public_and_the_tree_is_not
deep_filters_are_refused_before_they_recurse
critical_controls_are_refused_and_others_ignored
wide_filters_are_refused
out_of_range_limits_are_refused_without_panicking
a_rebind_refused_for_a_control_drops_the_identity
the_time_limit_is_honoured
the_time_limit_holds_for_the_last_candidate
search_fields_are_type_checked
integer_equality_is_numeric_and_undefined_for_non_integers
hidden_members_are_neither_shown_nor_matched
an_attribute_with_only_hidden_values_is_omitted
server_limits_cap_the_root_dse
the_time_limit_holds_while_the_base_is_resolved
nested_fields_are_type_checked
unknown_attribute_types_are_undefined
dn_values_match_by_parsed_name
empty_and_or_are_refused
server_limits_cap_unlimited_searches
message_id_zero_is_refused
extensible_matches_are_shape_checked
attribute_selectors_are_bounded
substring_items_count_against_the_budget
text_matching_uses_ldap_string_preparation
substrings_need_a_substrings_rule
a_wide_filter_is_refused_before_its_children_are_held
ldap::tests::preparation_uses_full_case_folding
an_entry_found_after_the_deadline_is_not_returned
every_request_is_shape_checked
the_entry_cap_is_checked_before_building_the_entry
ordering_follows_the_attribute
binds_are_checked
framing_unbind_and_malformed_requests
an_administrator_sees_the_emulated_tree_marked
a_disabled_shared_mailbox_still_receives
the_security_flag_is_kept_as_read
nesting_follows_every_group
a_user_s_groups_follow_nesting_upward
members_and_groups_are_inverse
group_properties_are_a_quack_filter
empty_property_junctions_are_identities
mail_is_chained_addressing
only_a_security_group_passes_on_its_sid
a_version_s_memberships_are_followed
ad_group_type_sets_the_flag
departure_by_conversion_to_shared_keeps_the_mailbox
an_unknown_lifecycle_is_not_a_recipient
casing_does_not_change_the_identity
identity_not_ordinal_reaches_change_diff_plan_and_provenance
a_mail_on_another_object_is_a_label_not_a_claim
a_mail_label_on_another_object_is_not_a_claim
a_departed_user_holds_no_address_and_receives_nothing
offboarding_by_disable_remote_mailbox_stops_delivery
a_remote_mailbox_with_its_cloud_mailbox_receives
a_remote_mailbox_without_a_cloud_mailbox_receives_nothing
two_cloud_mailboxes_are_not_one
contradicting_witnesses_are_not_a_mailbox
an_on_premises_mailbox_needs_no_cloud_mailbox
the_cloud_never_revives_a_non_recipient
an_empty_on_premises_exchange_guid_awaits_backsync
a_matching_exchange_guid_is_migratable
a_mismatched_exchange_guid_blocks_the_cloud_mailbox
an_unread_or_ambiguous_cloud_exchange_guid_decides_nothing
the_exchange_guid_comparison_needs_a_remote_mailbox_in_the_cloud
identity_is_read_by_guid
mail_hydrates_no_identity
mail_is_a_business_card_property_as_written
mail_follows_the_user_through_offboarding
no_mailbox_no_exchange_guid
from_ad_reads_the_exchange_guid_from_schema_6_only
EOF
exit "$missing"
iam-immutability:
name: IAM immutability
runs-on: ubuntu-24.04
timeout-minutes: 20
defaults:
run:
working-directory: lance-graph
steps:
- uses: actions/checkout@v4
with:
path: lance-graph
persist-credentials: false
# lance-graph-rbac itself depends only on lance-graph-contract, but it
# is a workspace member, and loading the workspace reads every member's
# manifest, including the ones that path-dep ndarray and OGAR.
- name: Checkout AdaWorldAPI/ndarray (sibling, needed to load the workspace)
uses: actions/checkout@v4
with:
repository: AdaWorldAPI/ndarray
path: ndarray
persist-credentials: false
- name: Checkout AdaWorldAPI/OGAR (sibling, needed to load the workspace)
uses: actions/checkout@v4
with:
repository: AdaWorldAPI/OGAR
path: OGAR
persist-credentials: false
- name: Setup rust toolchain (pinned by rust-toolchain.toml)
run: rustup show
# `.cargo/config.toml` builds with target-cpu=native, and cargo's
# fingerprint sees the flag text, not the CPU: an artifact built on a
# runner with AVX-512 would be reused on one without and die with
# SIGILL. Spell `native` out as this runner's exact feature list:
# a different CPU then gives different flags, cargo recompiles by itself,
# and the cache is keyed to the same flags.
- name: Resolve target-cpu=native for this runner
id: cpu
run: |
flags=$(.github/scripts/resolve-native-rustflags.sh)
echo "RUSTFLAGS=$flags" >> "$GITHUB_ENV"
hash=$(printf %s "$flags" | sha256sum | cut -c1-16)
echo "flags=$hash" >> "$GITHUB_OUTPUT"
echo "native is \`$(.github/scripts/resolve-native-rustflags.sh --cpu)\`, features $hash, job \`$GITHUB_JOB\`" >> "$GITHUB_STEP_SUMMARY"
- uses: Swatinem/rust-cache@v2
with:
key: cpu-${{ steps.cpu.outputs.flags }}
workspaces: lance-graph/crates/lance-graph-rbac
- name: Run the IAM tests
run: cargo test --manifest-path crates/lance-graph-rbac/Cargo.toml
- name: The tests pinning the immutable principal exist
run: |
cargo test -q --manifest-path crates/lance-graph-rbac/Cargo.toml -- --list \
> "$RUNNER_TEMP/tests.txt"
missing=0
while read -r name; do
[ -z "$name" ] && continue
if ! grep -Fxq "$name: test" "$RUNNER_TEMP/tests.txt"; then
echo "::error::missing pinning test: $name"
missing=1
fi
done <<'EOF'
auth::tests::resolved_identity_feeds_authorize
auth::tests::a_delegated_identity_authorizes_as_the_principal
auth::tests::an_undelegated_identity_acts_as_itself
auth::tests::the_outermost_act_is_the_current_actor
auth::tests::a_provider_without_tokens_cannot_be_delegated
auth::tests::the_acting_party_keeps_its_issuer
EOF
exit "$missing"