Skip to content

Add OAuth agent login and signed rotating API keys #42

Add OAuth agent login and signed rotating API keys

Add OAuth agent login and signed rotating API keys #42

name: Integration regression closure
on:
push:
paths:
- '.github/workflows/integration-regressions.yml'
- 'src/msg/transports/http_routes.py'
- 'src/msg/transports/http.py'
- 'src/msg/plugins/discovery.py'
- 'src/msg/plugins/read_predicates.py'
- 'src/msg/security/quarantine.py'
- 'src/msg/core/executor.py'
- 'src/msg/plugins/communication.py'
- 'src/msg/security/oauth.py'
- 'src/msg/transports/oauth_http.py'
- 'src/msg/client_oauth.py'
- 'src/msg/client_api_keys.py'
- 'src/msg/oauth_config.py'
- 'src/msg/plugins/oauth_identity.py'
- 'src/msg/plugins/identity.py'
- 'src/msg/security/authentication.py'
- 'src/msg/security/capabilities.py'
- 'src/msg/core/models.py'
- 'src/msg/config.py'
- 'src/msg/config_contracts.py'
- 'src/msg/client.py'
- 'src/msg/cli.py'
- 'src/msg/storage/postgres.py'
- 'src/msg/storage/sqlite.py'
- 'src/msg/storage/session.py'
- 'src/msg/storage/read_only.py'
- 'tests/test_oauth.py'
- 'tests/test_http_effect_order.py'
- 'tests/test_read_entry_contract_matrix.py'
- 'tests/test_read_query_keyset_boundary.py'
- 'tests/test_recovery_runtime_generation.py'
- 'tests/read_only_evidence.py'
- 'tests/test_legacy_routes_removed.py'
- 'tests/test_webhook*.py'
pull_request:
paths:
- '.github/workflows/integration-regressions.yml'
- 'src/msg/transports/http_routes.py'
- 'src/msg/transports/http.py'
- 'src/msg/plugins/discovery.py'
- 'src/msg/plugins/read_predicates.py'
- 'src/msg/security/quarantine.py'
- 'src/msg/core/executor.py'
- 'src/msg/plugins/communication.py'
- 'src/msg/security/oauth.py'
- 'src/msg/transports/oauth_http.py'
- 'src/msg/client_oauth.py'
- 'src/msg/client_api_keys.py'
- 'src/msg/oauth_config.py'
- 'src/msg/plugins/oauth_identity.py'
- 'src/msg/plugins/identity.py'
- 'src/msg/security/authentication.py'
- 'src/msg/security/capabilities.py'
- 'src/msg/core/models.py'
- 'src/msg/config.py'
- 'src/msg/config_contracts.py'
- 'src/msg/client.py'
- 'src/msg/cli.py'
- 'src/msg/storage/postgres.py'
- 'src/msg/storage/sqlite.py'
- 'src/msg/storage/session.py'
- 'src/msg/storage/read_only.py'
- 'tests/test_oauth.py'
- 'tests/test_http_effect_order.py'
- 'tests/test_read_entry_contract_matrix.py'
- 'tests/test_read_query_keyset_boundary.py'
- 'tests/test_recovery_runtime_generation.py'
- 'tests/read_only_evidence.py'
- 'tests/test_legacy_routes_removed.py'
- 'tests/test_webhook*.py'
workflow_dispatch:
inputs:
expected_sha:
description: 'Optional full commit SHA; fail before running code if the selected ref moved'
required: false
type: string
permissions:
contents: read
concurrency:
group: integration-regressions-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
regression:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
locale: ['C', 'en_US.utf8']
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: msgtest
POSTGRES_PASSWORD: msgtest
POSTGRES_DB: postgres
POSTGRES_INITDB_ARGS: --encoding=UTF8 --locale=${{ matrix.locale }}
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U msgtest -d postgres"
--health-interval 10s --health-timeout 5s --health-retries 5
env:
MSG_TEST_POSTGRES_URL_TEMPLATE: postgresql://msgtest:msgtest@127.0.0.1:5432/{database}
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Record exact source identity
env:
EXPECTED_SHA: ${{ inputs.expected_sha }}
TEST_DATABASE_LOCALE: ${{ matrix.locale }}
run: |
if [ -n "$EXPECTED_SHA" ]; then
test "$(git rev-parse HEAD)" = "$EXPECTED_SHA"
fi
mkdir -p artifacts
python3 - <<'PY'
import json, os, subprocess
from pathlib import Path
def git(*args):
return subprocess.check_output(['git', *args], text=True).strip()
Path('artifacts/source.json').write_text(json.dumps({
'commit': git('rev-parse', 'HEAD'), 'tree': git('rev-parse', 'HEAD^{tree}'),
'run_id': os.environ['GITHUB_RUN_ID'], 'attempt': os.environ['GITHUB_RUN_ATTEMPT'],
'requested_database_locale': os.environ['TEST_DATABASE_LOCALE']}, indent=2) + '\n')
PY
- name: Preserve reviewed public source even when tests fail
uses: actions/upload-artifact@v7.0.1
with:
name: integration-regression-source-${{ matrix.locale }}
path: |
artifacts/source.json
src/
tests/
scripts/
conftest.py
pyproject.toml
CONTRIBUTING.md
if-no-files-found: error
- uses: actions/setup-python@v7
with:
python-version: '3.15'
allow-prereleases: true
cache: pip
- name: Install actual cryptographic and database dependencies
run: |
sudo apt-get update -qq
sudo env NEEDRESTART_MODE=l apt-get install -y -qq age
python -m pip install -e '.[dev]'
- name: Record and require the actual database locale
env:
EXPECTED_DATABASE_LOCALE: ${{ matrix.locale }}
run: |
python - <<'PY'
import json, os, platform
from pathlib import Path
import psycopg
dsn = os.environ['MSG_TEST_POSTGRES_URL_TEMPLATE'].format(database='postgres')
with psycopg.connect(dsn) as connection:
server_version = connection.execute('SHOW server_version').fetchone()[0]
locale_row = connection.execute(
"SELECT datcollate,datctype,pg_encoding_to_char(encoding) "
"FROM pg_database WHERE datname=current_database()"
).fetchone()
assert locale_row is not None
values = {
'server_version': server_version,
'lc_collate': locale_row[0],
'lc_ctype': locale_row[1],
'server_encoding': locale_row[2],
'python': platform.python_version(),
}
Path('artifacts/database.json').write_text(json.dumps(values, indent=2) + '\n')
assert values['lc_collate'] == os.environ['EXPECTED_DATABASE_LOCALE'], values
assert values['server_encoding'] == 'UTF8', values
PY
- name: Run recovery, keyset, effect-order, path and webhook regressions
run: >-
python -m pytest -q
tests/test_oauth.py
tests/test_http_effect_order.py tests/test_legacy_routes_removed.py
tests/test_read_query_keyset_boundary.py tests/test_read_entry_contract_matrix.py
tests/test_recovery_runtime_generation.py
tests/test_stable_resource_views.py tests/test_canonical_post_paths.py
tests/test_webhook_overlap.py tests/test_webhook_domain_events.py
tests/test_webhook_delivery.py tests/test_webhook_identity.py
--junitxml=artifacts/integration-regressions.xml
- uses: actions/upload-artifact@v7.0.1
if: always()
with:
name: integration-regression-evidence-${{ matrix.locale }}
path: artifacts/
if-no-files-found: error