From b309e18cf30e7575a4f355105bb834f7f809a97b Mon Sep 17 00:00:00 2001 From: Derek Higgins Date: Fri, 5 Dec 2025 12:29:22 +0000 Subject: [PATCH] test(ci): add ABAC testing with files API to auth tests Add ABAC testing to integration-auth-tests workflow: o Enable files and inference APIs o Configure localfs files provider o Add access policy for file ownership validation o Create multiple service accounts (user1, user2) o Move API Access tests into standalone script o Test file policy with both users Signed-off-by: Derek Higgins --- .github/workflows/integration-auth-tests.yml | 75 +++++++------- scripts/integration-auth-tests.sh | 101 +++++++++++++++++++ 2 files changed, 135 insertions(+), 41 deletions(-) create mode 100755 scripts/integration-auth-tests.sh diff --git a/.github/workflows/integration-auth-tests.yml b/.github/workflows/integration-auth-tests.yml index 28781c6803..52f446d892 100644 --- a/.github/workflows/integration-auth-tests.yml +++ b/.github/workflows/integration-auth-tests.yml @@ -20,6 +20,7 @@ on: - 'pyproject.toml' - 'requirements.txt' - '.github/workflows/integration-auth-tests.yml' # This workflow + - 'scripts/integration-auth-tests.sh' concurrency: group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.ref }} @@ -54,8 +55,10 @@ jobs: if: ${{ matrix.auth-provider == 'oauth2_token' }} run: | kubectl create namespace llama-stack - kubectl create serviceaccount llama-stack-auth -n llama-stack - kubectl create token llama-stack-auth -n llama-stack > llama-stack-auth-token + for account in llama-stack-auth llama-stack-user1 llama-stack-user2; do + kubectl create serviceaccount $account -n llama-stack + kubectl create token $account -n llama-stack > $account-token + done - name: Set Kubernetes Config if: ${{ matrix.auth-provider == 'oauth2_token' }} @@ -75,8 +78,18 @@ jobs: cat < $run_dir/run.yaml version: '2' image_name: kube - apis: [] - providers: {} + apis: + - files + - inference + providers: + files: + - provider_id: meta-reference-files + provider_type: inline::localfs + config: + storage_dir: $run_dir/files + metadata_store: + table_name: files_metadata + backend: sql_default storage: backends: kv_default: @@ -100,6 +113,21 @@ jobs: backend: kv_default server: port: 8321 + auth: + access_policy: + - permit: + actions: [read, delete] + resource: sql_record::openai_files::* + when: + - user with system:serviceaccount:llama-stack:llama-stack-user1 in roles + - user in owners roles + description: User1 can read and delete their Files + - permit: + actions: [read] + resource: sql_record::openai_files::* + when: + - user in owners roles + description: Owners can read their Files EOF yq eval '.server.auth.provider_config.type = "${{ matrix.auth-provider }}"' -i $run_dir/run.yaml yq eval '.server.auth.provider_config.tls_cafile = "${{ env.KUBERNETES_CA_CERT_PATH }}"' -i $run_dir/run.yaml @@ -137,40 +165,5 @@ jobs: - name: Test auth run: | - # Function to test API endpoint with authentication - # Usage: test_endpoint [output_file] - test_endpoint() { - local curl_args="$1" - local user_token_file=$2 - local expected_status=$3 - local output_file=${4:-/dev/null} - - local status - local extra_curl_args=(-s -L -o "$output_file" -w "%{http_code}") - - if [ "$user_token_file" != "none" ]; then - extra_curl_args+=(-H "Authorization: Bearer $(cat $user_token_file)") - fi - - set -x - status=$(curl $curl_args "${extra_curl_args[@]}") - set +x - - if [ "$status" = "$expected_status" ]; then - echo " ✓ Status: $status (expected $expected_status)" - return 0 - else - echo " ✗ Status: $status (expected $expected_status)" - exit 1 - fi - } - - echo "Testing /v1/version without token (should succeed)..." - test_endpoint "http://127.0.0.1:8321/v1/version" "none" "200" || exit 1 - - echo "Testing /v1/providers without token (should fail with 401)..." - test_endpoint "http://127.0.0.1:8321/v1/providers" "none" "401" || exit 1 - - echo "Testing /v1/providers with valid token (should succeed)..." - test_endpoint "http://127.0.0.1:8321/v1/providers" "llama-stack-auth-token" "200" "providers.json" || exit 1 - cat providers.json | jq . > /dev/null && echo " ✓ Valid JSON response" + # Run the auth tests + ./scripts/integration-auth-tests.sh diff --git a/scripts/integration-auth-tests.sh b/scripts/integration-auth-tests.sh new file mode 100755 index 0000000000..9271ba68d2 --- /dev/null +++ b/scripts/integration-auth-tests.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +set -euo pipefail + +# Integration auth tests for Llama Stack +# This script tests authentication and authorization (ABAC) functionality +# Expects token files to be created before running (e.g., by CI workflow or manual setup) + +# Function to test API endpoint with authentication +# Usage: test_endpoint [output_file] +test_endpoint() { + local curl_args="$1" + local user_token_file=$2 + local expected_status=$3 + local output_file=${4:-/dev/null} + + local status + local extra_curl_args=(-s -L -o "$output_file" -w "%{http_code}") + + if [ "$user_token_file" != "none" ]; then + extra_curl_args+=(-H "Authorization: Bearer $(cat $user_token_file)") + fi + + set -x + status=$(curl $curl_args "${extra_curl_args[@]}") + set +x + + if [ "$status" = "$expected_status" ]; then + echo " ✓ Status: $status (expected $expected_status)" + return 0 + else + echo " ✗ Status: $status (expected $expected_status)" + exit 1 + fi +} + +# Check if user tokens exist for ABAC testing +if [ ! -f "llama-stack-auth-token" ] || [ ! -f "llama-stack-user1-token" ] || [ ! -f "llama-stack-user2-token" ]; then + echo "" + echo "❌ User tokens not found - expected llama-stack-user1-token and llama-stack-user2-token" + exit 1 +fi + +echo "Testing /v1/version without token (should succeed)..." +test_endpoint "http://127.0.0.1:8321/v1/version" "none" "200" || exit 1 + +echo "Testing /v1/providers without token (should fail with 401)..." +test_endpoint "http://127.0.0.1:8321/v1/providers" "none" "401" || exit 1 + +echo "Testing /v1/providers with valid token (should succeed)..." +test_endpoint "http://127.0.0.1:8321/v1/providers" "llama-stack-auth-token" "200" "providers.json" || exit 1 +cat providers.json | jq . > /dev/null && echo " ✓ Valid JSON response" + +echo "" +echo "Running ABAC tests with user tokens..." + +# Create test file +echo "test content" > test-file.txt + +echo "Both user1 and user2 can create files..." +test_endpoint "http://127.0.0.1:8321/v1/files -F file=@test-file.txt -F purpose=assistants" "llama-stack-user1-token" "200" "user1-files.json" || exit 1 +test_endpoint "http://127.0.0.1:8321/v1/files -F file=@test-file.txt -F purpose=assistants" "llama-stack-user2-token" "200" "user2-files.json" || exit 1 + +echo "user1 can only read their own files..." +test_endpoint "http://127.0.0.1:8321/v1/files" "llama-stack-user1-token" "200" "user1-files-list.json" || exit 1 +USER1_FILE_COUNT=$(jq '.data|length' user1-files-list.json) +echo "User1 has $USER1_FILE_COUNT file(s)" +[ $USER1_FILE_COUNT -eq 1 ] || ( echo " ✗ User1 should have 1 file, but has $USER1_FILE_COUNT" && exit 1 ) +echo " ✓ User1 can see exactly 1 file" + +echo "user2 can read their own file..." +test_endpoint "http://127.0.0.1:8321/v1/files" "llama-stack-user2-token" "200" "user2-files-list.json" || exit 1 +USER2_FILE_COUNT=$(jq '.data|length' user2-files-list.json) +echo "User2 has $USER2_FILE_COUNT file(s)" +[ $USER2_FILE_COUNT -eq 1 ] || ( echo " ✗ User2 should have 1 file, but has $USER2_FILE_COUNT" && exit 1 ) +echo " ✓ User2 can see their own file" + +echo "Both file ids should differ" +FILEID_USER1=$(jq -r '.data[0].id' user1-files-list.json) +FILEID_USER2=$(jq -r '.data[0].id' user2-files-list.json) +[ "$FILEID_USER1" != "$FILEID_USER2" ] || ( echo " ✗ File IDs should differ" && exit 1 ) +echo " ✓ File IDs differ" + +echo "user2 can't delete their own file or other users' files..." +test_endpoint "http://127.0.0.1:8321/v1/files/$FILEID_USER2 -X DELETE" "llama-stack-user2-token" "404" || exit 1 +test_endpoint "http://127.0.0.1:8321/v1/files/$FILEID_USER1 -X DELETE" "llama-stack-user2-token" "404" || exit 1 +echo " ✓ Delete correctly blocked" + +echo "user1 can delete their own files but not other users' files..." +test_endpoint "http://127.0.0.1:8321/v1/files/$FILEID_USER1 -X DELETE" "llama-stack-user1-token" "200" || exit 1 +echo " ✓ Delete successful" +test_endpoint "http://127.0.0.1:8321/v1/files/$FILEID_USER2 -X DELETE" "llama-stack-user1-token" "404" || exit 1 +echo " ✓ Delete correctly blocked" + +echo "" +echo "✓ ABAC test completed successfully!"