Skip to content

Commit 7792cc4

Browse files
authored
Merge pull request #276 from finos/feat/backend-hardening
feat(backend): security hardening + provider_api invariant + expanded API surface + alembic migrations
2 parents 3738fee + 7a8f1c6 commit 7792cc4

292 files changed

Lines changed: 25925 additions & 5058 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-quality.yml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ on:
3535
- '.ruff.toml'
3636
- '.github/workflows/ci-quality.yml'
3737

38+
# Cancel in-progress runs when a new push arrives on the same branch/ref.
39+
# The auto-format job is exempted via its own job-level concurrency block
40+
# (cancel-in-progress: false) because it pushes a commit back to the branch —
41+
# cancelling it mid-push could leave the branch in a partially formatted state.
42+
concurrency:
43+
group: ci-${{ github.workflow }}-${{ github.ref }}
44+
cancel-in-progress: true
45+
3846
permissions:
3947
contents: read
4048

@@ -91,11 +99,20 @@ jobs:
9199

92100
auto-format:
93101
name: Auto-Format Code
94-
# Same-repo PRs only: push commits as the ORB CICD App.
95-
# Fork PRs are handled by the auto-format-suggest job below.
96-
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
102+
# Same-repo PRs only. Fork PRs handled by auto-format-suggest below.
103+
# Bot-actor guard prevents the job re-triggering on its own push.
104+
if: |
105+
github.event_name == 'pull_request'
106+
&& github.event.pull_request.head.repo.full_name == github.repository
107+
&& github.actor != 'open-resource-broker-cicd[bot]'
97108
runs-on: ubuntu-latest
98109
needs: [config, setup-cache]
110+
# Override the workflow-level concurrency so this job is never cancelled
111+
# mid-run. If it were interrupted after `ruff` rewrites files but before
112+
# `git push`, the PR branch would be left in a half-formatted state.
113+
concurrency:
114+
group: ci-auto-format-${{ github.ref }}
115+
cancel-in-progress: false
99116
permissions:
100117
contents: write
101118
steps:
@@ -134,7 +151,7 @@ jobs:
134151
run: |
135152
git add .
136153
if ! git diff --staged --quiet; then
137-
git commit -m "style: auto-format code with ruff [skip ci]"
154+
git commit -m "style: auto-format code with ruff"
138155
git push
139156
fi
140157

.github/workflows/ci-tests.yml

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ on:
2222
schedule:
2323
- cron: '0 2 * * *'
2424

25+
# Cancel in-progress runs when a new push arrives on the same branch/ref.
26+
# Scheduled nightly runs use a stable group key so they never cancel each
27+
# other (there is only ever one running at a time by schedule).
28+
concurrency:
29+
group: ci-${{ github.workflow }}-${{ github.ref }}
30+
cancel-in-progress: true
31+
2532
permissions:
2633
contents: read
2734

@@ -84,12 +91,21 @@ jobs:
8491
environment: ${{ needs.config.outputs.environment }}
8592
testing-flag: ${{ needs.config.outputs.testing-flag }}
8693

87-
onmoto-tests:
88-
name: Onmoto Tests (Default Python)
94+
# Per-provider matrix. One job per provider subtree under
95+
# tests/providers/. New providers land here as new matrix entries —
96+
# no separate onmoto job needed (moto-mocked tests live under
97+
# tests/providers/aws/moto and run as part of the aws entry).
98+
providers-tests:
99+
name: Providers Tests
89100
needs: [config, setup-cache]
101+
strategy:
102+
fail-fast: false
103+
matrix:
104+
provider: [aws]
90105
uses: ./.github/workflows/reusable-test.yml
91106
with:
92-
test-type: onmoto
107+
test-type: providers
108+
provider: ${{ matrix.provider }}
93109
python-version: ${{ needs.config.outputs.default-python-version }}
94110
default-python-version: ${{ needs.config.outputs.default-python-version }}
95111
continue-on-error: false
@@ -99,12 +115,25 @@ jobs:
99115
environment: ${{ needs.config.outputs.environment }}
100116
testing-flag: ${{ needs.config.outputs.testing-flag }}
101117

102-
providers-tests:
103-
name: Providers & Infrastructure Tests (Default Python)
104-
needs: [config, setup-cache]
118+
# Serial-marked provider tests (currently the live-AWS subtree).
119+
# The make target points pytest directly at ``tests/providers/<provider>/live``
120+
# because ``norecursedirs`` excludes that path from auto-recursion. Without
121+
# ``--live`` the root conftest stamps every live test with ``skip_live``, so
122+
# the job collects the suite, reports SKIPPED, and exits 0 — that proves the
123+
# collection wiring + skip mechanism still work end-to-end on every PR.
124+
# When CI is wired up with real AWS credentials, set ``PYTEST_LIVE=--live``
125+
# in the workflow env to flip the suite into actual execution.
126+
providers-tests-serial:
127+
name: Providers Tests (Serial)
128+
needs: [config, setup-cache, providers-tests]
129+
strategy:
130+
fail-fast: false
131+
matrix:
132+
provider: [aws]
105133
uses: ./.github/workflows/reusable-test.yml
106134
with:
107-
test-type: providers
135+
test-type: providers-serial
136+
provider: ${{ matrix.provider }}
108137
python-version: ${{ needs.config.outputs.default-python-version }}
109138
default-python-version: ${{ needs.config.outputs.default-python-version }}
110139
continue-on-error: false
@@ -161,7 +190,7 @@ jobs:
161190
test-report:
162191
name: Generate Test Report
163192
runs-on: ubuntu-latest
164-
needs: [config, setup-cache, tests, integration-tests, e2e-tests, onmoto-tests, providers-tests, infrastructure-tests]
193+
needs: [config, setup-cache, tests, integration-tests, e2e-tests, providers-tests, providers-tests-serial, infrastructure-tests]
165194
if: always()
166195
permissions:
167196
contents: read

.github/workflows/reusable-test.yml

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ on:
44
workflow_call:
55
inputs:
66
test-type:
7-
description: 'Type of tests to run (unit, integration, e2e, performance)'
7+
description: 'Type of tests to run (unit, integration, e2e, performance, providers, infrastructure)'
88
required: true
99
type: string
10+
provider:
11+
description: 'When test-type=providers, scope the run to a single provider subtree (e.g. aws, k8s).'
12+
required: false
13+
type: string
14+
default: ''
1015
python-version:
1116
description: 'Python version to test with'
1217
required: false
@@ -65,7 +70,7 @@ env:
6570

6671
jobs:
6772
test:
68-
name: ${{ inputs.test-type == 'unit' && 'Unit Tests' || inputs.test-type == 'integration' && 'Integration Tests' || inputs.test-type == 'e2e' && 'End-to-End Tests' || format('{0} Tests', inputs.test-type) }}
73+
name: ${{ inputs.test-type == 'unit' && 'Unit Tests' || inputs.test-type == 'integration' && 'Integration Tests' || inputs.test-type == 'e2e' && 'End-to-End Tests' || (inputs.test-type == 'providers' && inputs.provider != '') && format('Providers Tests ({0})', inputs.provider) || format('{0} Tests', inputs.test-type) }}
6974
runs-on: ${{ inputs.os }}
7075
permissions:
7176
contents: read
@@ -81,14 +86,32 @@ jobs:
8186
fail-on-cache-miss: false
8287

8388
- name: Run tests
84-
run: make ci-tests-${{ inputs.test-type }}
89+
id: run-tests
90+
run: make ci-tests-${{ inputs.test-type }} PROVIDER=${{ inputs.provider }}
8591
continue-on-error: ${{ inputs.continue-on-error }}
8692

93+
# When continue-on-error is true the overall job status stays green even
94+
# if tests fail, which can hide regressions in the PR summary view.
95+
# This step fires only on failure and writes a visible warning to the
96+
# GitHub job summary so operators notice the failure without digging into
97+
# the raw log.
98+
- name: Annotate soft failure in job summary
99+
if: steps.run-tests.outcome == 'failure'
100+
run: |
101+
echo "::warning::${{ inputs.test-type }} tests failed (continue-on-error=true). Review the test log for details."
102+
{
103+
echo "## :warning: ${{ inputs.test-type }} test failures"
104+
echo ""
105+
echo "The **${{ inputs.test-type }}** test suite reported failures."
106+
echo "Overall job status is still green because \`continue-on-error: true\` is set,"
107+
echo "but these failures should be investigated before merging."
108+
} >> "$GITHUB_STEP_SUMMARY"
109+
87110
- name: Upload test results
88111
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
89112
if: always()
90113
with:
91-
name: test-results-${{ inputs.test-type }}-${{ inputs.os }}-py${{ inputs.python-version || inputs.default-python-version }}
114+
name: test-results-${{ inputs.test-type }}${{ inputs.provider != '' && format('-{0}', inputs.provider) || '' }}-${{ inputs.os }}-py${{ inputs.python-version || inputs.default-python-version }}
92115
retention-days: 30
93116
path: |
94117
junit-*.xml
@@ -100,14 +123,14 @@ jobs:
100123
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6
101124
with:
102125
token: ${{ secrets.CODECOV_TOKEN }}
103-
files: coverage-${{ inputs.test-type }}.xml
104-
flags: ${{ inputs.test-type }}
105-
name: ${{ inputs.test-type }}-tests
126+
files: coverage-${{ inputs.test-type }}${{ inputs.provider != '' && format('-{0}', inputs.provider) || '' }}.xml
127+
flags: ${{ inputs.test-type }}${{ inputs.provider != '' && format('-{0}', inputs.provider) || '' }}
128+
name: ${{ inputs.test-type }}${{ inputs.provider != '' && format('-{0}', inputs.provider) || '' }}-tests
106129

107130
- name: Upload test results to Codecov
108131
if: ${{ !cancelled() }}
109132
continue-on-error: true
110133
uses: codecov/test-results-action@0fa95f0e1eeaafde2c782583b36b28ad0d8c77d3 # v1
111134
with:
112135
token: ${{ secrets.CODECOV_TOKEN }}
113-
files: junit-${{ inputs.test-type }}.xml
136+
files: junit-${{ inputs.test-type }}${{ inputs.provider != '' && format('-{0}', inputs.provider) || '' }}.xml

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.states
2+
.web
3+
reflex.lock/
4+
assets/external/
15
# Generated files
26
# pyproject.toml is now tracked - only metadata is templated, dependencies managed by Dependabot
37

@@ -279,3 +283,6 @@ coverage.json
279283

280284
# Backup files from editors/tools
281285
*.bak*
286+
287+
# Per-package coverage artifacts (never commit)
288+
coverage-*.xml

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,28 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
88
<!-- insertion marker -->
99
## Unreleased
1010

11+
### BREAKING CHANGES
12+
13+
- **Daemon token file at `<work_dir>/server/orb-server.token`.**
14+
When `orb server start` is invoked (daemon or `--foreground` mode), a
15+
random bearer token is written to `<work_dir>/server/orb-server.token`
16+
with mode `0600`. The CLI reads this file to authenticate loopback admin
17+
requests such as `orb server reload`. The file is removed when the daemon
18+
exits. Operators who snapshot the work directory should exclude
19+
`*.token` from backups.
20+
21+
- **`allow_destructive_admin` config field (default `false`).**
22+
Administrative endpoints that can wipe state (purge, bulk-delete, etc.)
23+
now require `allow_destructive_admin: true` in the server config. The
24+
field defaults to `false` and must be opted in explicitly.
25+
26+
- **SQL storage strategy applies Alembic migrations on startup.**
27+
When `storage.strategy` is `sql`, the server now runs `alembic upgrade
28+
head` automatically on startup. Operators using a managed database
29+
(RDS, Aurora) should ensure the database user has DDL privileges, or run
30+
migrations out-of-band with `orb db upgrade` before starting the server
31+
with `allow_auto_migrate: false`.
32+
1133
### Added
1234

1335
- New `[aws]` extra (alias for AWS deps currently in core). The canonical install

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ The container supports multiple entry points:
330330
docker run --rm image --version
331331

332332
# API server
333-
docker run -p 8000:8000 image system serve
333+
docker run -p 8000:8000 image server start --foreground
334334

335335
# Health check
336336
docker run --rm image --health

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
recursive-include config *.json
22
recursive-include scripts *.sh *.bat
3+
include src/orb/ui/rxconfig.py

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ See the [CLI Reference](docs/root/cli/cli-reference.md) for the full flag refere
229229
<details>
230230
<summary>REST API</summary>
231231

232-
Example API calls. Requires `pip install "orb-py[api]"` and `orb system serve`.
232+
Example API calls. Requires `pip install "orb-py[api]"` and `orb server start` (add `--foreground` for an in-shell variant).
233233

234234
```bash
235235
# Get available templates

0 commit comments

Comments
 (0)