Skip to content
Merged
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
21 changes: 21 additions & 0 deletions .agents/skills/swiftui-pro/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Paul Hudson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
16 changes: 12 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ jobs:
worker:
name: Worker and tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
Expand All @@ -35,22 +36,29 @@ jobs:
run: npm run test:worker
- name: Build Worker
run: npm run build
- name: Check forward-compatible D1 migrations
run: npm run migrations:check
- name: Smoke-test local API and Auth stack
run: npm run dev:smoke

ios:
name: iOS Simulator build
runs-on: macos-15
timeout-minutes: 20
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Test iOS helpers
run: npm run test:ios
- name: Run iOS unit tests
run: npm run ios:test:unit
- name: Build unsigned iOS app
run: >-
xcodebuild
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
languages: javascript-typescript
- name: Analyze
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
23 changes: 23 additions & 0 deletions .github/workflows/dco.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-License-Identifier: Apache-2.0
name: DCO

on:
pull_request:

permissions:
contents: read

jobs:
signoff:
name: Developer Certificate of Origin
runs-on: ubuntu-latest
steps:
- name: Check out pull request history
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
- name: Check commit sign-offs
env:
DCO_BASE_SHA: ${{ github.event.pull_request.base.sha }}
DCO_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: node scripts/check-dco.mjs
35 changes: 28 additions & 7 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ jobs:
timeout-minutes: 20
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
Expand All @@ -49,6 +49,8 @@ jobs:
run: npm run test:worker
- name: Build production Workers without uploading
run: npm run build:production
- name: Check forward-compatible D1 migrations
run: npm run migrations:check

deploy:
name: Deploy Auth then API
Expand All @@ -58,26 +60,30 @@ jobs:
environment: production
env:
CI: "true"
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Require Cloudflare deployment credentials
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
shell: bash
run: |
set -euo pipefail
test -n "${CLOUDFLARE_ACCOUNT_ID:?}"
test -n "${CLOUDFLARE_API_TOKEN:?}"
- name: Capture rollback versions
id: rollback_versions
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
shell: bash
run: |
set -euo pipefail
Expand All @@ -89,18 +95,30 @@ jobs:
echo "auth_version=$auth_version" >> "$GITHUB_OUTPUT"
echo "api_version=$api_version" >> "$GITHUB_OUTPUT"
- name: Apply Auth D1 migrations
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: npm run d1:migrate:auth:production
- name: Deploy Auth Worker
id: deploy_auth
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: >-
npm run deploy:auth:production --
--message "GitHub ${GITHUB_SHA}: deploy Bellwire Auth"
- name: Verify Auth production boundary
run: npm run verify:auth:production
- name: Apply business D1 migrations
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: npm run d1:migrate:api:production
- name: Deploy API Worker
id: deploy_api
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: >-
npm run deploy:api:production --
--message "GitHub ${GITHUB_SHA}: deploy Bellwire API"
Expand All @@ -118,8 +136,11 @@ jobs:
echo "- API: https://api.bellwire.app/health"
echo "- Order: Auth D1 → Auth Worker → Auth verification → Business D1 → API Worker → full verification"
} >> "$GITHUB_STEP_SUMMARY"
- name: Roll back deployed Worker versions after failure
- name: Roll back Worker code after failure; D1 migrations stay forward-only
if: ${{ failure() && (steps.deploy_auth.outcome == 'success' || steps.deploy_api.outcome == 'success') }}
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
shell: bash
run: |
set -euo pipefail
Expand Down
32 changes: 27 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Validate release metadata and license payloads
env:
RELEASE_TAG: ${{ github.ref_name }}
run: npm run release:check
- name: Lint
run: npm run lint
- name: Typecheck
Expand All @@ -37,16 +41,18 @@ jobs:
runs-on: macos-15
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Test iOS helpers
run: npm run test:ios
- name: Run iOS unit tests
run: npm run ios:test:unit
- name: Build unsigned iOS app
run: >-
xcodebuild
Expand All @@ -68,14 +74,28 @@ jobs:
contents: write
steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Set up Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Validate release metadata and license payloads
env:
RELEASE_TAG: ${{ github.ref_name }}
run: npm run release:check
- name: Package Agent Skill
run: |
cd skills
zip -r -X "../bellwire-skill-${GITHUB_REF_NAME}.zip" bellwire
cd ..
unzip -t "bellwire-skill-${GITHUB_REF_NAME}.zip"
unzip -p "bellwire-skill-${GITHUB_REF_NAME}.zip" bellwire/LICENSE | grep -q "MIT No Attribution"
sha256sum "bellwire-skill-${GITHUB_REF_NAME}.zip" > "bellwire-skill-${GITHUB_REF_NAME}.zip.sha256"
- name: Generate CycloneDX npm SBOM
run: npm sbom --sbom-format=cyclonedx > "bellwire-npm-${GITHUB_REF_NAME}.cdx.json"
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -86,3 +106,5 @@ jobs:
--generate-notes
"bellwire-skill-${GITHUB_REF_NAME}.zip"
"bellwire-skill-${GITHUB_REF_NAME}.zip.sha256"
"bellwire-npm-${GITHUB_REF_NAME}.cdx.json"
"THIRD_PARTY_NOTICES.md"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ wrangler.auth.self-host.toml
wrangler.*.local.toml
.wrangler/
ios/Bellwire/Configuration/Local.xcconfig
ios/Bellwire/Bellwire/Assets.xcassets/SelfHostedAppIcon.appiconset/
*.local
*.p8

Expand Down
28 changes: 27 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ All notable changes to Bellwire are documented here. The project follows

## [Unreleased]

## [0.2.0] - 2026-08-08

### Added

- Add an explicit hosted/self-hosted entitlement contract so self-hosted
deployments keep export and Live Activity features without App Store billing.
- Add required self-hosted app-name, app-icon, support, and legal configuration,
with bootstrap and doctor validation that keeps Bellwire brand assets out of
redistributed forks.
- Add a one-command local API/Auth development stack, real iOS entitlement unit
tests, machine-readable OpenAPI, telemetry, upgrade, and security operations
documentation.
- Add DCO enforcement, migration safety checks, release metadata validation,
third-party notices, and a CycloneDX npm SBOM release artifact.

### Changed

- Pin GitHub Actions to full commit SHAs and scope Cloudflare deployment
credentials to only the steps that require them.
- Make D1 rollback policy explicitly forward-only and keep Worker code rollback
separate from schema migration recovery.
- Move compact iOS text tokens to semantic Dynamic Type styles and make support,
legal, product, display-name, and keychain identifiers deployment-aware.
- Generate six-digit pairing codes with rejection sampling to avoid modulo bias.

## [0.1.3] - 2026-08-08

### Fixed
Expand Down Expand Up @@ -85,7 +110,8 @@ All notable changes to Bellwire are documented here. The project follows
- Bellwire name, app icon, and official service identifiers reserved under the
trademark policy.

[Unreleased]: https://github.com/wegoft/bellwire/compare/v0.1.3...HEAD
[Unreleased]: https://github.com/wegoft/bellwire/compare/v0.2.0...HEAD
[0.2.0]: https://github.com/wegoft/bellwire/compare/v0.1.3...v0.2.0
[0.1.3]: https://github.com/wegoft/bellwire/compare/v0.1.2...v0.1.3
[0.1.2]: https://github.com/wegoft/bellwire/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/wegoft/bellwire/compare/v0.1.0...v0.1.1
Expand Down
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ npm ci
npm run lint
npm run typecheck
npm test
npm run migrations:check
npm run build
npm run ios:test:unit
npm run ios:build
```

Expand All @@ -46,7 +48,8 @@ git commit -s

The `Signed-off-by` line certifies the contribution under the
[Developer Certificate of Origin](https://developercertificate.org/). Do not
sign off on code you do not have the right to contribute.
sign off on code you do not have the right to contribute. Pull requests run an
automated DCO check; bot-authored dependency updates are exempt.

## Contribution licensing

Expand Down
30 changes: 30 additions & 0 deletions GOVERNANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- SPDX-License-Identifier: Apache-2.0 -->

# Governance

Bellwire uses maintainer-led governance while the project is in `0.x` releases.
The goal is predictable technical decisions with a clear path for community
participation.

## Decisions

- Routine fixes and documentation changes are accepted through review by a
maintainer.
- API, protocol, storage, authentication, licensing, and default-delivery
changes require an issue or architecture decision record before merge.
- Security fixes may be developed privately and disclosed after supported
deployments can be updated.
- The project lead has final responsibility for release, trademark, hosted
service, and incident decisions. Rationale should be recorded publicly when
disclosure is safe.

## Contributions and releases

All non-bot commits require a Developer Certificate of Origin sign-off. Pull
requests must pass CI, CodeQL, DCO, license-boundary, migration, and relevant iOS
checks. Releases use Semantic Versioning for the repository distribution; the
iOS marketing version, API version, and D1 migration identifiers are separate
compatibility axes described in [the upgrading guide](docs/upgrading.md).

Maintainers are listed in [MAINTAINERS.md](MAINTAINERS.md). Project conduct is
governed by [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
Loading