Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 68 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,36 @@ env:
RUST_VERSION: '1.85'

jobs:
changes:
name: Check for changes
runs-on: ubuntu-latest
outputs:
typescript: ${{ steps.filter.outputs.typescript }}
rust: ${{ steps.filter.outputs.rust }}
load_tests: ${{ steps.filter.outputs.load_tests }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Detect changes
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
typescript:
- 'src/**'
- 'app/**'
- 'backend/**'
- 'package.json'
- 'package-lock.json'
- 'tsconfig.json'
- 'jest.config.js'
- 'App.tsx'
- 'index.ts'
rust:
- 'contracts/**'
load_tests:
- 'load-tests/**'

commitlint:
name: Conventional Commit Check
runs-on: ubuntu-latest
Expand Down Expand Up @@ -38,6 +68,8 @@ jobs:
# ─────────────────────────────────────────────────────────
typescript-lint:
name: TypeScript Lint & Format
needs: changes
if: needs.changes.outputs.typescript == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -60,6 +92,8 @@ jobs:

npm-audit:
name: NPM Audit (High/Critical)
needs: changes
if: needs.changes.outputs.typescript == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -79,6 +113,8 @@ jobs:

typescript-typecheck:
name: TypeScript Type Check
needs: changes
if: needs.changes.outputs.typescript == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -101,6 +137,8 @@ jobs:

typescript-tests:
name: TypeScript Tests (Sharded)
needs: changes
if: needs.changes.outputs.typescript == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -124,7 +162,7 @@ jobs:
- name: Run sharded tests with coverage
run: |
echo "Running shard $SHARD of $SHARD_COUNT"
npm run test:shard
npm run test:shard -- --shard=${{ matrix.shard }}/${{ env.SHARD_COUNT }}

- name: Upload coverage report
uses: actions/upload-artifact@v4
Expand All @@ -134,6 +172,8 @@ jobs:

typescript-build:
name: TypeScript Build
needs: changes
if: needs.changes.outputs.typescript == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand Down Expand Up @@ -164,11 +204,12 @@ jobs:
with:
fetch-depth: 0

- name: Download coverage report
- name: Download all coverage reports
uses: actions/download-artifact@v4
with:
name: coverage-report
pattern: coverage-report-*
path: coverage
merge-multiple: false

- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
Expand All @@ -181,6 +222,8 @@ jobs:
# ─────────────────────────────────────────────────────────
rust-format:
name: Rust Format Check
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -197,6 +240,8 @@ jobs:

rust-clippy:
name: Rust Clippy Lint
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -219,6 +264,8 @@ jobs:

rust-tests:
name: Rust Tests
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -240,6 +287,8 @@ jobs:

rust-build:
name: Rust Build
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -264,6 +313,8 @@ jobs:
# ─────────────────────────────────────────────────────────
load-test:
name: k6 Load Test
needs: changes
if: needs.changes.outputs.load_tests == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -284,6 +335,7 @@ jobs:
if: github.event_name == 'pull_request'
needs:
[
changes,
commitlint,
typescript-lint,
typescript-typecheck,
Expand All @@ -309,6 +361,7 @@ jobs:
if: always()
needs:
[
changes,
commitlint,
typescript-lint,
typescript-typecheck,
Expand All @@ -324,21 +377,21 @@ jobs:
steps:
- name: Check for failures
run: |
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ needs.commitlint.result }}" != "success" ]; then
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ needs.commitlint.result }}" != "success" ] && [ "${{ needs.commitlint.result }}" != "skipped" ]; then
echo "Conventional commit check failed"
exit 1
fi
if [ "${{ needs.typescript-lint.result }}" != "success" ] || \
[ "${{ needs.typescript-typecheck.result }}" != "success" ] || \
[ "${{ needs.typescript-tests.result }}" != "success" ] || \
[ "${{ needs.typescript-build.result }}" != "success" ] || \
[ "${{ needs.sonarcloud.result }}" != "success" ] || \
[ "${{ needs.rust-format.result }}" != "success" ] || \
[ "${{ needs.rust-clippy.result }}" != "success" ] || \
[ "${{ needs.rust-tests.result }}" != "success" ] || \
[ "${{ needs.rust-build.result }}" != "success" ] || \
[ "${{ needs.load-test.result }}" != "success" ]; then
if [ "${{ needs.typescript-lint.result }}" != "success" ] && [ "${{ needs.typescript-lint.result }}" != "skipped" ] || \
[ "${{ needs.typescript-typecheck.result }}" != "success" ] && [ "${{ needs.typescript-typecheck.result }}" != "skipped" ] || \
[ "${{ needs.typescript-tests.result }}" != "success" ] && [ "${{ needs.typescript-tests.result }}" != "skipped" ] || \
[ "${{ needs.typescript-build.result }}" != "success" ] && [ "${{ needs.typescript-build.result }}" != "skipped" ] || \
[ "${{ needs.sonarcloud.result }}" != "success" ] && [ "${{ needs.sonarcloud.result }}" != "skipped" ] || \
[ "${{ needs.rust-format.result }}" != "success" ] && [ "${{ needs.rust-format.result }}" != "skipped" ] || \
[ "${{ needs.rust-clippy.result }}" != "success" ] && [ "${{ needs.rust-clippy.result }}" != "skipped" ] || \
[ "${{ needs.rust-tests.result }}" != "success" ] && [ "${{ needs.rust-tests.result }}" != "skipped" ] || \
[ "${{ needs.rust-build.result }}" != "success" ] && [ "${{ needs.rust-build.result }}" != "skipped" ] || \
[ "${{ needs.load-test.result }}" != "success" ] && [ "${{ needs.load-test.result }}" != "skipped" ]; then
echo "One or more CI checks failed"
exit 1
fi
echo "All CI checks passed successfully!"
echo "All CI checks passed (or were skipped) successfully!"
14 changes: 11 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ on:
workflow_dispatch:
inputs:
deploy:
description: 'Deployment target (canary|prod)'
description: 'Deployment target (canary|prod|rollback)'
required: true
default: 'canary'
version:
description: 'Version to rollback to (optional, defaults to last tag)'
required: false

permissions:
contents: write
Expand Down Expand Up @@ -105,8 +108,13 @@ jobs:
- name: Checkout previous tag
run: |
git fetch --tags
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1)
git checkout $PREV_TAG
if [ -n "${{ github.event.inputs.version }}" ]; then
TARGET_TAG="${{ github.event.inputs.version }}"
else
TARGET_TAG=$(git describe --tags --abbrev=0 HEAD~1)
fi
echo "Rolling back to $TARGET_TAG"
git checkout $TARGET_TAG

- name: Setup Node.js
uses: actions/setup-node@v4
Expand Down
8 changes: 7 additions & 1 deletion backend/services/__tests__/auditService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,17 @@ describe('AuditService', () => {
// ── Retention policy ──────────────────────────────────────────────────────

it('prunes events older than retention window', () => {
const svcShort = new AuditService(SECRET, { maxAgeMs: 0 }); // expire immediately
jest.useFakeTimers();
const svcShort = new AuditService(SECRET, { maxAgeMs: 1000 });
svcShort.capture('subscription.created', 'a', 'r', 'subscription');

// Advance time by 2 seconds to ensure event is expired
jest.advanceTimersByTime(2000);

const pruned = svcShort.applyRetention();
expect(pruned).toBe(1);
expect(svcShort.query({})).toHaveLength(0);
jest.useRealTimers();
});

it('keeps events within retention window', () => {
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
preset: 'jest-expo',
transformIgnorePatterns: [
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|@walletconnect/.*)',
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|@walletconnect/.*|@superfluid-finance/.*)',
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
collectCoverageFrom: ['src/**/*.{ts,tsx}', 'chaos/**/*.ts', '!src/**/*.d.ts', '!src/**/index.ts'],
Expand Down
Loading
Loading