/* * test_aud_check.c — unit tests for M1: aud claim exact match + array form. * * Tests string exact match, substring rejection, array form pass/fail. * See docs/plans/junie/pg_knoe_auth-rename-harden-modularize.md §2.2.4 */ #include "test_helpers.h" /* * aud_contains — copied verbatim from pg_knoe_auth.c so we can test it * without linking against PostgreSQL. */ static bool aud_contains(const char *aud_value, const char *expected) { if (!aud_value || !expected) return false; /* Array form: ["val1","val2",...] */ if (aud_value[0] == '[') { const char *p = aud_value + 1; while (*p) { const char *elem_start, *elem_end; size_t elem_len; while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; if (*p == ']' || *p == '\0') break; if (*p != '"') break; p++; elem_start = p; while (*p && *p != '"') { if (*p == '\\') p++; if (*p) p++; } elem_end = p; if (*p == '"') p++; elem_len = (size_t)(elem_end - elem_start); if (elem_len == strlen(expected) && strncmp(elem_start, expected, elem_len) == 0) return true; } return false; } /* String form: exact equality */ return strcmp(aud_value, expected) == 0; } int main(void) { /* String form — exact match */ ASSERT( aud_contains("pg.0.knoe.dev", "pg.0.knoe.dev"), "string exact match passes"); /* String form — substring must NOT pass (old strstr bug) */ ASSERT(!aud_contains("evil.pg.0.knoe.dev", "pg.0.knoe.dev"), "substring of expected in aud string is rejected"); ASSERT(!aud_contains("pg.0.knoe.dev.evil", "pg.0.knoe.dev"), "expected as prefix of aud string is rejected"); /* String form — wrong value */ ASSERT(!aud_contains("other.service", "pg.0.knoe.dev"), "wrong string aud is rejected"); /* Array form — single element match */ ASSERT( aud_contains("[\"pg.0.knoe.dev\"]", "pg.0.knoe.dev"), "array with matching element passes"); /* Array form — multiple elements, one matches */ ASSERT( aud_contains("[\"other\",\"pg.0.knoe.dev\",\"more\"]", "pg.0.knoe.dev"), "array with matching element among others passes"); /* Array form — no element matches */ ASSERT(!aud_contains("[\"other\",\"service\"]", "pg.0.knoe.dev"), "array without matching element is rejected"); /* Array form — substring element must NOT match */ ASSERT(!aud_contains("[\"evil.pg.0.knoe.dev\"]", "pg.0.knoe.dev"), "array element that is superset of expected is rejected"); /* NULL inputs */ ASSERT(!aud_contains(NULL, "pg.0.knoe.dev"), "NULL aud_value is rejected"); ASSERT(!aud_contains("pg.0.knoe.dev", NULL), "NULL expected is rejected"); TEST_SUMMARY(); }