Merge public-prelaunch: open-source launch prep + FIPS unit-fallback coverage + companion safe-area fix
All checks were successful
Demo images / Build & push demo images (push) Successful in 3m10s
All checks were successful
Demo images / Build & push demo images (push) Successful in 3m10s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
94b5374f66
18
.github/pull_request_template.md
vendored
18
.github/pull_request_template.md
vendored
@ -1,16 +1,16 @@
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<!-- Brief description of what this PR does -->
|
<!-- What changed and why? -->
|
||||||
|
|
||||||
## Changes
|
## Verification
|
||||||
|
|
||||||
-
|
<!-- Commands run, devices tested, screenshots, or reason testing was not run. -->
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
- [ ] TypeScript type-check passes (`npm run type-check`)
|
- [ ] Rust formatting/clippy/tests pass when backend code changed.
|
||||||
- [ ] Frontend builds (`npm run build`)
|
- [ ] Frontend type-check/build/tests pass when frontend code changed.
|
||||||
- [ ] Tests pass (`npm test`)
|
- [ ] App manifests validate when app packaging changed.
|
||||||
- [ ] Rust clippy clean (if backend changes)
|
- [ ] Generated catalogs are updated when manifest-owned catalog fields changed.
|
||||||
- [ ] No new compiler warnings
|
- [ ] Docs are updated for user-facing or developer-facing behavior changes.
|
||||||
- [ ] Tested on live server
|
- [ ] No secrets, generated build outputs, local screenshots, or private host details are included.
|
||||||
|
|||||||
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@ -8,11 +8,11 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
RUST_VERSION: stable
|
RUST_VERSION: stable
|
||||||
NODE_VERSION: 18
|
NODE_VERSION: 20
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
rust:
|
rust:
|
||||||
name: Rust (fmt + clippy + test)
|
name: Rust
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@ -28,17 +28,17 @@ jobs:
|
|||||||
toolchain: ${{ env.RUST_VERSION }}
|
toolchain: ${{ env.RUST_VERSION }}
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Format
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
|
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy --all-targets --all-features -- -D warnings
|
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
- name: Tests
|
- name: Test
|
||||||
run: cargo test --all-features
|
run: cargo test --all-features
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
name: Frontend (type-check + lint)
|
name: Frontend
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@ -52,14 +52,31 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: 'npm'
|
cache: npm
|
||||||
cache-dependency-path: neode-ui/package-lock.json
|
cache-dependency-path: neode-ui/package-lock.json
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Type check
|
- name: Type check
|
||||||
run: npm run type-check
|
run: npm run type-check
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: npm test
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
|
manifests:
|
||||||
|
name: App Manifests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate manifests
|
||||||
|
run: |
|
||||||
|
for manifest in apps/*/manifest.yml; do
|
||||||
|
./scripts/validate-app-manifest.sh --repo-audit "$manifest"
|
||||||
|
done
|
||||||
|
|||||||
35
.gitignore
vendored
35
.gitignore
vendored
@ -1,10 +1,9 @@
|
|||||||
# SSH keys (sandbox copies)
|
# SSH keys and sandbox copies
|
||||||
.ssh/
|
.ssh/
|
||||||
|
|
||||||
# Rust build output
|
# Rust build output
|
||||||
target/
|
target/
|
||||||
**/target/
|
**/target/
|
||||||
Cargo.lock
|
|
||||||
|
|
||||||
# Node.js
|
# Node.js
|
||||||
node_modules/
|
node_modules/
|
||||||
@ -12,7 +11,6 @@ node_modules/
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
package-lock.json
|
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
|
|
||||||
# Build outputs
|
# Build outputs
|
||||||
@ -28,49 +26,46 @@ build/
|
|||||||
*.swo
|
*.swo
|
||||||
*~
|
*~
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
._*
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
# Environment and local overrides
|
# Environment and local overrides
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
.env.production
|
||||||
|
core/.env.production
|
||||||
scripts/deploy-config.sh
|
scripts/deploy-config.sh
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs/
|
logs/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# OS
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
coverage/
|
coverage/
|
||||||
.nyc_output/
|
.nyc_output/
|
||||||
|
|
||||||
# Temporary files
|
# Image / release artifacts
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
|
|
||||||
# Build artifacts
|
|
||||||
*.iso
|
*.iso
|
||||||
*.img
|
*.img
|
||||||
*.dmg
|
*.dmg
|
||||||
*.app
|
*.app
|
||||||
|
*.apk
|
||||||
|
*.keystore
|
||||||
|
*.s9pk
|
||||||
|
*.tar.gz
|
||||||
|
|
||||||
# Release artifacts live in Gitea Release attachments, not Git history.
|
# Release artifacts live in release attachments, not Git history.
|
||||||
releases/**
|
releases/**
|
||||||
!releases/
|
!releases/
|
||||||
!releases/manifest.json
|
!releases/manifest.json
|
||||||
|
|
||||||
# macOS build output
|
|
||||||
build/macos/
|
|
||||||
|
|
||||||
# Image recipe output
|
# Image recipe output
|
||||||
image-recipe/output/
|
image-recipe/output/
|
||||||
image-recipe/*.iso
|
image-recipe/*.iso
|
||||||
image-recipe/*.img
|
image-recipe/*.img
|
||||||
|
|
||||||
# Loop tool artifacts (created in every subdirectory)
|
# Loop tool artifacts
|
||||||
*/loop/
|
*/loop/
|
||||||
loop/loop/
|
loop/loop/
|
||||||
loop/loop.log.bak
|
loop/loop.log.bak
|
||||||
@ -78,19 +73,17 @@ loop/loop.log.bak
|
|||||||
# Separate repos nested in tree
|
# Separate repos nested in tree
|
||||||
web/
|
web/
|
||||||
|
|
||||||
._*
|
# Resilience harness reports contain session cookies.
|
||||||
|
|
||||||
# Resilience harness reports (generated, contains session cookies)
|
|
||||||
scripts/resilience/reports/
|
scripts/resilience/reports/
|
||||||
|
|
||||||
# Codex / pnpm / python caches / editor backups
|
# Codex / pnpm / python caches / editor backups
|
||||||
.codex
|
.codex
|
||||||
.codex-target-*/
|
.codex-target-*/
|
||||||
.codex-tmp/
|
.codex-tmp/
|
||||||
|
.claude/
|
||||||
.pnpm-store/
|
.pnpm-store/
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
*.bak
|
*.bak
|
||||||
.claude/scheduled_tasks.lock
|
|
||||||
|
|
||||||
# Local evidence screenshots; intentional UI screenshots should live under an
|
# Local evidence screenshots; intentional UI screenshots should live under an
|
||||||
# app/docs asset path with a descriptive filename.
|
# app/docs asset path with a descriptive filename.
|
||||||
|
|||||||
Binary file not shown.
@ -197,6 +197,12 @@ private fun injectSafeAreaVars(view: WebView) {
|
|||||||
* the status-bar height: the padded strip shows the page's OWN background
|
* the status-bar height: the padded strip shows the page's OWN background
|
||||||
* (padding is inside the element), so the bar keeps the page colour while
|
* (padding is inside the element), so the bar keeps the page colour while
|
||||||
* content starts below it — the pre-edge-to-edge look, without the black bar.
|
* content starts below it — the pre-edge-to-edge look, without the black bar.
|
||||||
|
*
|
||||||
|
* Body padding only moves normal-flow content. fixed/sticky elements anchored
|
||||||
|
* at the viewport top (IndeeHub's floating header) stayed glued under the
|
||||||
|
* status bar, so we also push each of those down by the inset — once, marked
|
||||||
|
* via data attribute — and keep a throttled MutationObserver running so
|
||||||
|
* headers an SPA mounts after load get the same treatment.
|
||||||
* Idempotent; runs on start (early) and finish (after the app rewrites head). */
|
* Idempotent; runs on start (early) and finish (after the app rewrites head). */
|
||||||
private fun injectTopInset(view: WebView) {
|
private fun injectTopInset(view: WebView) {
|
||||||
val insets = view.rootWindowInsets ?: return
|
val insets = view.rootWindowInsets ?: return
|
||||||
@ -206,6 +212,7 @@ private fun injectTopInset(view: WebView) {
|
|||||||
view.evaluateJavascript(
|
view.evaluateJavascript(
|
||||||
"""
|
"""
|
||||||
(function() {
|
(function() {
|
||||||
|
var SAT = $sat;
|
||||||
var s = document.getElementById('archy-top-inset');
|
var s = document.getElementById('archy-top-inset');
|
||||||
if (!s) {
|
if (!s) {
|
||||||
s = document.createElement('style');
|
s = document.createElement('style');
|
||||||
@ -213,7 +220,40 @@ private fun injectTopInset(view: WebView) {
|
|||||||
(document.head || document.documentElement).appendChild(s);
|
(document.head || document.documentElement).appendChild(s);
|
||||||
}
|
}
|
||||||
s.textContent =
|
s.textContent =
|
||||||
'body{padding-top:${sat}px!important;box-sizing:border-box!important;}';
|
'body{padding-top:' + SAT + 'px!important;box-sizing:border-box!important;}';
|
||||||
|
function push(el) {
|
||||||
|
if (el.dataset.archyInset) return;
|
||||||
|
var cs = getComputedStyle(el);
|
||||||
|
if (cs.position !== 'fixed' && cs.position !== 'sticky') return;
|
||||||
|
var top = parseFloat(cs.top); // 'auto' -> NaN skips bottom bars
|
||||||
|
if (isNaN(top) || top >= SAT) return;
|
||||||
|
el.style.setProperty('top', (top + SAT) + 'px', 'important');
|
||||||
|
el.dataset.archyInset = '1';
|
||||||
|
}
|
||||||
|
function sweep() {
|
||||||
|
if (!document.body) return;
|
||||||
|
// Fixed/sticky bars live shallow in the tree (portals mount on
|
||||||
|
// body); depth cap keeps the computed-style pass off big lists.
|
||||||
|
var els = document.body.querySelectorAll(
|
||||||
|
'body > *, body > * > *, body > * > * > *, body > * > * > * > *');
|
||||||
|
for (var i = 0; i < els.length; i++) push(els[i]);
|
||||||
|
}
|
||||||
|
sweep();
|
||||||
|
if (!window.__archyInsetObserver) {
|
||||||
|
var queued = false, last = 0;
|
||||||
|
window.__archyInsetObserver = new MutationObserver(function() {
|
||||||
|
if (queued) return;
|
||||||
|
queued = true;
|
||||||
|
var wait = Math.max(0, 250 - (Date.now() - last));
|
||||||
|
setTimeout(function() {
|
||||||
|
queued = false;
|
||||||
|
last = Date.now();
|
||||||
|
sweep();
|
||||||
|
}, wait);
|
||||||
|
});
|
||||||
|
window.__archyInsetObserver.observe(document.documentElement,
|
||||||
|
{ childList: true, subtree: true });
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
null,
|
null,
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.7.117-alpha (2026-07-27)
|
||||||
|
|
||||||
|
- FIPS startup is more reliable on nodes that have the packaged `fips.service` instead of Archipelago's `archipelago-fips.service`. Startup self-heal, onboarding, dashboard Start, and reconnect now use the systemd unit the node actually has, so FIPS no longer looks like it needs to be installed when it only needs to be started.
|
||||||
|
- App screens over the FIPS mesh now bind their relay only to the node's FIPS address instead of reserving the same host ports Podman needs. This keeps apps such as FileBrowser and Botfights from restart-looping because the backend was already holding their published ports.
|
||||||
|
- Companion WebView safe-area handling now also moves fixed and sticky top bars below the phone status bar, including headers mounted after page load by single-page apps.
|
||||||
|
- Public-source preparation now includes a Nostr Git hosting plan using `ngit`, NIP-34, and GRASP: anyone can clone, fork, review, and propose changes from their Archipelago node, while canonical merge authority stays with a small signed maintainer set in the style of Bitcoin Core.
|
||||||
|
- Node OS release notes for v1.7.117 are still open; add any installer, service, kernel, firewall, or package changes here before cutting the release.
|
||||||
|
|
||||||
## v1.7.116-alpha (2026-07-27)
|
## v1.7.116-alpha (2026-07-27)
|
||||||
|
|
||||||
- Nodes no longer get stuck on "server starting up" after an update or reboot. On a node running many apps, the backend used to spend minutes recovering containers before it told the system it was ready, and anything that touched it during that window could leave it down for good. It now reports ready immediately and recovers in the background, and it always restarts itself if it ever does go down.
|
- Nodes no longer get stuck on "server starting up" after an update or reboot. On a node running many apps, the backend used to spend minutes recovering containers before it told the system it was ready, and anything that touched it during that window could leave it down for good. It now reports ready immediately and recovers in the background, and it always restarts itself if it ever does go down.
|
||||||
|
|||||||
19
CODE_OF_CONDUCT.md
Normal file
19
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Code of Conduct
|
||||||
|
|
||||||
|
## Our standard
|
||||||
|
|
||||||
|
Be direct, respectful, and focused on the work. Healthy disagreement is welcome;
|
||||||
|
harassment, personal attacks, and discriminatory language are not.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This code of conduct applies to project repositories, issue trackers, pull
|
||||||
|
requests, documentation, chat, and community spaces connected to Archipelago.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Maintainers may edit, hide, or remove comments and may restrict participation
|
||||||
|
for behavior that makes collaboration unsafe or unproductive.
|
||||||
|
|
||||||
|
Report conduct concerns privately through the repository owner account or the
|
||||||
|
private contact channel listed on the project homepage.
|
||||||
191
CONTRIBUTING.md
191
CONTRIBUTING.md
@ -1,161 +1,100 @@
|
|||||||
# Contributing to Archipelago
|
# Contributing to Archipelago
|
||||||
|
|
||||||
Thank you for your interest in contributing to Archipelago! This document covers the process for contributing code, reporting bugs, and submitting apps.
|
This project is preparing for public developer contribution. The highest-value
|
||||||
|
contributions are focused fixes, tests, app manifests, documentation
|
||||||
|
improvements, and clear bug reports with reproducible evidence.
|
||||||
|
|
||||||
## Code of Conduct
|
## Development setup
|
||||||
|
|
||||||
Be respectful. We follow the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
### Frontend
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
1. Fork the repository on the project's Gitea instance
|
|
||||||
2. Clone your fork: `git clone <your-fork-url>/archy.git`
|
|
||||||
3. Set up the dev environment (see `docs/developer-guide.md`)
|
|
||||||
4. Create a feature branch: `git checkout -b feature/your-feature`
|
|
||||||
|
|
||||||
## Development Setup
|
|
||||||
|
|
||||||
### Frontend (Vue.js)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd neode-ui
|
cd neode-ui
|
||||||
npm install
|
npm install
|
||||||
npm start # Dev server on :8100
|
npm start
|
||||||
npm run type-check # TypeScript validation
|
npm run type-check
|
||||||
npm run build # Production build
|
npm test
|
||||||
npm test # Run tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backend (Rust)
|
### Backend
|
||||||
|
|
||||||
Build on a Linux server (Debian 13), **not** macOS:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo clippy --all-targets --all-features
|
cd core
|
||||||
cargo fmt --all
|
cargo fmt --all -- --check
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
cargo test --all-features
|
cargo test --all-features
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deploy to dev server
|
Linux is required for host integration work involving Podman, systemd,
|
||||||
|
networking, or image builds. Frontend development works locally with the mock
|
||||||
|
backend.
|
||||||
|
|
||||||
|
## App manifests
|
||||||
|
|
||||||
|
App packages live under `apps/<app-id>/manifest.yml` and use the schema
|
||||||
|
documented in [docs/app-manifest-spec.md](docs/app-manifest-spec.md). Validate
|
||||||
|
before submitting:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/deploy-to-target.sh --live
|
./scripts/validate-app-manifest.sh apps/<app-id>/manifest.yml
|
||||||
|
python3 scripts/generate-app-catalog.py
|
||||||
|
python3 scripts/check-app-catalog-drift.py --release --strict
|
||||||
```
|
```
|
||||||
|
|
||||||
## Code Style
|
App submissions must:
|
||||||
|
|
||||||
### Frontend (TypeScript + Vue)
|
- pin container image versions;
|
||||||
|
- avoid hardcoded secrets;
|
||||||
|
- use `security.no_new_privileges: true`;
|
||||||
|
- use `security.readonly_root: true` unless the manifest explains why writable
|
||||||
|
root is required;
|
||||||
|
- request only necessary Linux capabilities;
|
||||||
|
- store durable data under `/var/lib/archipelago/<app-id>/`;
|
||||||
|
- define truthful health checks and launch interfaces for user-facing UIs.
|
||||||
|
|
||||||
- `<script setup lang="ts">` — always Composition API
|
## Code style
|
||||||
- TypeScript strict mode — no `any`, use `unknown` or proper types
|
|
||||||
- Global CSS classes in `src/style.css` — never inline Tailwind in components
|
|
||||||
- Pinia for state management — focused single-purpose stores
|
|
||||||
- Use `@/api/rpc-client.ts` for RPC calls
|
|
||||||
|
|
||||||
### Backend (Rust)
|
- Rust: prefer `?` over `unwrap()`/`expect()` in production paths.
|
||||||
|
- Rust: use `tracing` for structured logs.
|
||||||
|
- TypeScript: avoid `any`; use explicit types or `unknown`.
|
||||||
|
- Vue: prefer `<script setup lang="ts">`.
|
||||||
|
- Keep changes scoped; do not mix drive-by refactors with behavioral changes.
|
||||||
|
- Remove dead code rather than commenting it out.
|
||||||
|
- Add tests for new behavior and regression tests for bug fixes.
|
||||||
|
|
||||||
- No `unwrap()` or `expect()` in production code — use `?` operator
|
## Pull requests
|
||||||
- `thiserror` for library errors, `anyhow` for application errors
|
|
||||||
- `tracing` for structured logging — never `println!`
|
|
||||||
- Run `cargo clippy` and `cargo fmt` before commits
|
|
||||||
|
|
||||||
### General
|
1. Open one focused PR per behavior or documentation change.
|
||||||
|
2. Explain what changed, why it changed, and how it was verified.
|
||||||
|
3. Include screenshots for UI changes.
|
||||||
|
4. Link relevant issues or docs.
|
||||||
|
5. Keep generated catalog changes in sync with manifest changes.
|
||||||
|
|
||||||
- Functions under 50 lines, single responsibility
|
Suggested commit format:
|
||||||
- Comment WHY not WHAT
|
|
||||||
- Remove dead code — never comment it out
|
|
||||||
- No `TODO`/`FIXME` in commits
|
|
||||||
|
|
||||||
## Commit Format
|
```text
|
||||||
|
feat: add backup scheduling
|
||||||
```
|
fix: reject unsafe manifest volume
|
||||||
type: description
|
docs: clarify app deployment flow
|
||||||
|
test: cover catalog drift check
|
||||||
```
|
```
|
||||||
|
|
||||||
**Types**: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`, `perf:`
|
## Reporting bugs
|
||||||
|
|
||||||
Examples:
|
Include:
|
||||||
- `feat: add backup scheduling to settings page`
|
|
||||||
- `fix: handle WiFi connection timeout gracefully`
|
|
||||||
- `test: add unit tests for RPC client retry logic`
|
|
||||||
|
|
||||||
## Pull Request Process
|
- exact version or commit;
|
||||||
|
- host platform and architecture;
|
||||||
|
- steps to reproduce;
|
||||||
|
- expected and actual behavior;
|
||||||
|
- logs from the relevant component;
|
||||||
|
- screenshots for UI issues.
|
||||||
|
|
||||||
1. Ensure your branch is up to date with `main`
|
## Security
|
||||||
2. All checks must pass: TypeScript, build, tests, clippy
|
|
||||||
3. Include a clear description of what changed and why
|
|
||||||
4. Link any related issues
|
|
||||||
5. Request review from a maintainer
|
|
||||||
|
|
||||||
### PR Checklist
|
Do not report vulnerabilities in public issues. Follow [SECURITY.md](SECURITY.md).
|
||||||
|
|
||||||
- [ ] TypeScript type-check passes (`npm run type-check`)
|
|
||||||
- [ ] Frontend builds (`npm run build`)
|
|
||||||
- [ ] Tests pass (`npm test`)
|
|
||||||
- [ ] Rust clippy clean (`cargo clippy --all-targets --all-features`)
|
|
||||||
- [ ] No new compiler warnings
|
|
||||||
- [ ] Follows code style guidelines above
|
|
||||||
|
|
||||||
## Testing Requirements
|
|
||||||
|
|
||||||
- New features need tests
|
|
||||||
- Bug fixes need a regression test
|
|
||||||
- Frontend: Vitest + Vue Test Utils
|
|
||||||
- Backend: `#[test]` and `#[tokio::test]`
|
|
||||||
- Target: maintain or improve existing coverage
|
|
||||||
|
|
||||||
## Reporting Bugs
|
|
||||||
|
|
||||||
Use the **Bug Report** issue template. Include:
|
|
||||||
|
|
||||||
1. Steps to reproduce
|
|
||||||
2. Expected behavior
|
|
||||||
3. Actual behavior
|
|
||||||
4. System info (hardware, OS version, Archipelago version)
|
|
||||||
5. Screenshots if applicable
|
|
||||||
6. Relevant logs (`journalctl -u archipelago`)
|
|
||||||
|
|
||||||
## Feature Requests
|
|
||||||
|
|
||||||
Use the **Feature Request** issue template. Include:
|
|
||||||
|
|
||||||
1. Problem description
|
|
||||||
2. Proposed solution
|
|
||||||
3. Alternatives considered
|
|
||||||
4. Impact on existing users
|
|
||||||
|
|
||||||
## App Submissions
|
|
||||||
|
|
||||||
To submit an app for the Archipelago marketplace:
|
|
||||||
|
|
||||||
1. Create a manifest following `docs/app-manifest-spec.md`
|
|
||||||
2. Ensure the container image is published to a public registry
|
|
||||||
3. Test on Archipelago hardware (x86_64 and ARM64 if possible)
|
|
||||||
4. Open a PR adding the app to the curated list
|
|
||||||
5. Include: app description, icon, resource requirements, dependencies
|
|
||||||
|
|
||||||
### App Requirements
|
|
||||||
|
|
||||||
- Container must run as non-root (UID > 1000)
|
|
||||||
- `readonly_root: true` unless explicitly justified
|
|
||||||
- Drop all capabilities except those required
|
|
||||||
- `no-new-privileges: true`
|
|
||||||
- Pin specific image versions (no `latest` tag)
|
|
||||||
- No hardcoded secrets
|
|
||||||
|
|
||||||
## Security Disclosure
|
|
||||||
|
|
||||||
**Do NOT open public issues for security vulnerabilities.**
|
|
||||||
|
|
||||||
Email security concerns to the maintainers directly. Include:
|
|
||||||
|
|
||||||
1. Description of the vulnerability
|
|
||||||
2. Steps to reproduce
|
|
||||||
3. Potential impact
|
|
||||||
4. Suggested fix (if any)
|
|
||||||
|
|
||||||
We will acknowledge receipt within 48 hours and provide a timeline for a fix.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
By contributing, you agree that your contributions will be licensed under the same license as the project.
|
By contributing, you agree that your contribution is licensed under the
|
||||||
|
project's MIT License.
|
||||||
|
|||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Dorian and the Archipelago Project contributors
|
||||||
|
|
||||||
|
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.
|
||||||
73
NOTICE
Normal file
73
NOTICE
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Archipelago — Third-Party Notices
|
||||||
|
|
||||||
|
Archipelago is licensed under the MIT License (see LICENSE).
|
||||||
|
This file lists third-party components included in this repository and its
|
||||||
|
release artifacts, with their licenses and required attributions.
|
||||||
|
|
||||||
|
## Embedded / vendored components
|
||||||
|
|
||||||
|
- **FIPS mesh networking** — https://github.com/jmcorgan/fips
|
||||||
|
Copyright (c) 2026 Johnathan Corgan. MIT License.
|
||||||
|
Used as the embedded mesh VPN in the OS (`fips` daemon, pinned v0.4.1) and
|
||||||
|
compiled into the Android companion app (`Android/rust/archy-fips-core`).
|
||||||
|
|
||||||
|
- **QR Code Generator for JavaScript** — http://www.d-project.com/
|
||||||
|
Copyright (c) 2009 Kazuhiko Arase. MIT License.
|
||||||
|
Vendored at `docker/lnd-ui/qrcode.js` and `docker/electrs-ui/qrcode.js`
|
||||||
|
(original headers preserved).
|
||||||
|
|
||||||
|
- **nostr-rs-relay** — https://github.com/scsibug/nostr-rs-relay — MIT License.
|
||||||
|
Binary extracted into the OS image at `/opt/archipelago/bin/`.
|
||||||
|
|
||||||
|
- **Reticulum (RNS) and LXMF** — https://github.com/markqvist/Reticulum
|
||||||
|
Copyright Mark Qvist. Distributed under the Reticulum License (an MIT-style
|
||||||
|
license with field-of-use restrictions: no use in systems designed to harm
|
||||||
|
human beings, and no use in AI/ML training datasets). The optional
|
||||||
|
`archy-reticulum-daemon` binary bundles RNS 1.3.5 and LXMF 1.0.1. The
|
||||||
|
Reticulum License is NOT an OSI-approved open-source license; it applies
|
||||||
|
only to that optional component, not to Archipelago itself.
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
- **Montserrat** — SIL Open Font License 1.1
|
||||||
|
(`neode-ui/public/assets/fonts/Montserrat/OFL.txt`).
|
||||||
|
- **Open Sans** — Apache License 2.0
|
||||||
|
(`neode-ui/public/assets/fonts/Open_Sans/LICENSE.txt`).
|
||||||
|
|
||||||
|
## Artwork and icons
|
||||||
|
|
||||||
|
- **Mesh device artwork** (`neode-ui/public/assets/img/mesh-devices/`):
|
||||||
|
device illustrations from the Meshtastic project — https://meshtastic.org
|
||||||
|
© Meshtastic contributors, GPL-3.0. Meshtastic® is a registered trademark
|
||||||
|
of Meshtastic LLC. See the ATTRIBUTION.md in that directory.
|
||||||
|
- Some UI icons are derived from **game-icons.net** (CC BY 3.0 — see
|
||||||
|
ATTRIBUTION.md in `neode-ui/public/assets/icon/`) and **pixelarticons**
|
||||||
|
(MIT, https://github.com/halfmage/pixelarticons).
|
||||||
|
- Third-party application logos under `neode-ui/public/assets/img/app-icons/`
|
||||||
|
and `service-icons/` are trademarks of their respective owners, used solely
|
||||||
|
to identify the corresponding applications. No endorsement is implied.
|
||||||
|
|
||||||
|
## Original media
|
||||||
|
|
||||||
|
All demo content (music, photos, posters in `demo/`), UI sound effects,
|
||||||
|
background images, and intro video in `neode-ui/public/assets/` are original
|
||||||
|
works created and owned by the Archipelago project author, released with the
|
||||||
|
project. The welcome voice line (`welcome-noderunner.mp3`) was generated with
|
||||||
|
ElevenLabs TTS under a commercial-use plan.
|
||||||
|
|
||||||
|
## Redistributed software (ISO and container registry)
|
||||||
|
|
||||||
|
The Archipelago OS image is based on Debian and redistributes Debian packages
|
||||||
|
(including the Linux kernel, GRUB, and non-free firmware/microcode blobs
|
||||||
|
required for hardware support); per-package license texts are preserved at
|
||||||
|
`/usr/share/doc/*/copyright` in the installed system, and corresponding source
|
||||||
|
is available via Debian (https://snapshot.debian.org) as referenced in each
|
||||||
|
release's notes. Container images offered through the app catalog and mirror
|
||||||
|
registry remain under their upstream licenses (including GPL/AGPL software
|
||||||
|
such as mempool, Nextcloud, Vaultwarden, SearXNG, PhotoPrism, Immich,
|
||||||
|
Jellyfin, MariaDB, AdGuard Home, and strfry); source links are provided in
|
||||||
|
the app catalog. The modified mempool-frontend image is built from
|
||||||
|
`docker/mempool-frontend/` in this repository (AGPL-3.0 corresponding source).
|
||||||
|
|
||||||
|
Full per-crate and per-package license inventories for release binaries are
|
||||||
|
generated at build time (see THIRD-PARTY-LICENSES files in release artifacts).
|
||||||
229
README.md
229
README.md
@ -1,8 +1,11 @@
|
|||||||
# Archipelago
|
# Archipelago
|
||||||
|
|
||||||
> Self-Sovereign Bitcoin Node OS
|
> Self-sovereign Bitcoin node OS and manifest-driven app platform.
|
||||||
|
|
||||||
**Archipelago** is a bootable personal server OS. Flash it to a USB drive, install on any x86_64 or ARM64 machine, and manage Bitcoin infrastructure, self-hosted apps, mesh communication, and decentralized identity through a glassmorphism web UI.
|
Archipelago is a bootable personal server OS for Bitcoin infrastructure,
|
||||||
|
self-hosted apps, mesh communication, decentralized identity, and federation.
|
||||||
|
Apps are packaged as declarative `manifest.yml` files and run as rootless
|
||||||
|
Podman containers managed by the Rust backend.
|
||||||
|
|
||||||
[](https://www.debian.org/)
|
[](https://www.debian.org/)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
@ -10,193 +13,101 @@
|
|||||||
[](https://vuejs.org/)
|
[](https://vuejs.org/)
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
## Philosophy
|
## What is here
|
||||||
|
|
||||||
Archipelago is being built as a **developer-ready app platform**, not a fixed appliance:
|
- `core/` - Rust workspace: backend API, container runtime, security, OpenWrt
|
||||||
|
helpers, and performance/resource management.
|
||||||
|
- `neode-ui/` - Vue 3 + TypeScript frontend.
|
||||||
|
- `apps/` - app manifests and custom app container sources.
|
||||||
|
- `docker/` - supporting container build contexts for UI companion surfaces.
|
||||||
|
- `image-recipe/` - bootable image/ISO build inputs.
|
||||||
|
- `Android/` - Android companion app.
|
||||||
|
- `scripts/` - development, release, deployment, and validation tooling.
|
||||||
|
- `docs/` - architecture, app packaging, operations, API, and roadmap docs.
|
||||||
|
|
||||||
- **Manifest-driven apps.** Every app is declared in a single `manifest.yml` — image, ports, volumes, secrets, health checks, security policy. The orchestrator owns the entire lifecycle; there is no per-app installer code and no host-level provisioning.
|
## Platform model
|
||||||
- **Signed distribution.** App manifests ship inside an Ed25519-signed catalog verified against a pinned release-root key, not as loose files on disk. OTA release manifests are signed the same way.
|
|
||||||
- **Decentralized marketplace.** Third-party developers publish apps via Nostr-based discovery (NIP-78) with DID-signed manifests and federation-weighted trust scoring — no gatekept central store.
|
|
||||||
- **Rootless and secure by default.** Rootless Podman only. Read-only root, no-new-privileges, capability allow-list, secrets materialised 0600 and never logged. Never rootful, never a Docker socket mount.
|
|
||||||
- **100%-uptime-capable.** Every container is a systemd Quadlet unit under `user.slice` that survives backend restarts; a level-triggered reconciler self-heals drift every 30 seconds; migrations never destroy data.
|
|
||||||
|
|
||||||
## Features
|
Archipelago is built as a developer-ready app platform, not a fixed appliance:
|
||||||
|
|
||||||
### Bitcoin Infrastructure
|
- Apps are declared in `apps/<app-id>/manifest.yml`.
|
||||||
- **Bitcoin Core and Bitcoin Knots** full nodes with per-app version pinning and bulletproof version switching, automatic prune/full mode based on disk size
|
- The Rust parser in `core/container/src/manifest.rs` is the canonical schema.
|
||||||
- **LND** and **Core Lightning** with channel management
|
- The orchestrator compiles manifests to rootless Podman/Quadlet runtime state.
|
||||||
- **ElectrumX** Electrum server for wallet connectivity
|
- App data lives under `/var/lib/archipelago/<app-id>/`.
|
||||||
- **BTCPay Server** for accepting Bitcoin payments
|
- Secrets are generated or read from `/var/lib/archipelago/secrets/` and
|
||||||
- **Mempool** block explorer and fee estimator
|
injected through Podman secrets rather than static environment values.
|
||||||
- **Fedimint** federation guardian, gateway, and client — plus Cashu ecash wallet support
|
- Release and app catalogs are signed and verified against a pinned trust
|
||||||
|
anchor.
|
||||||
|
|
||||||
### Self-Hosted Apps (50+)
|
Start with:
|
||||||
Storage (FileBrowser, Immich, Nextcloud), Productivity (Vaultwarden), Media (Jellyfin, PhotoPrism, IndeeHub), Search (SearXNG), Network (NetBird, Tailscale), Home (Home Assistant), Nostr (nostr-rs-relay, strfry), Dev/Ops (Gitea, Grafana, Portainer, Uptime Kuma), and more — 27 curated in the store UI, 50+ packaged as manifests.
|
|
||||||
|
|
||||||
### Mesh Networking (tri-protocol)
|
- [Architecture](docs/architecture.md)
|
||||||
- **Meshtastic**, **MeshCore**, and **Reticulum (RNS/LXMF)** LoRa transports behind one mesh chat UI
|
- [Developer Guide](docs/developer-guide.md)
|
||||||
- End-to-end encryption with X3DH key agreement + double-ratchet
|
- [App Developer Guide](docs/app-developer-guide.md)
|
||||||
- RNode radio support with an OS-level `archy-rnodeconf` tool; interop verified against Sideband
|
- [App Manifest Spec](docs/app-manifest-spec.md)
|
||||||
- Image/voice attachments, mesh AI assistant (`!ai`), Bitcoin balance relay over mesh
|
- [Nostr Git Source Hosting Plan](docs/nostr-git-source-hosting.md)
|
||||||
|
- [Operations Runbook](docs/operations-runbook.md)
|
||||||
|
- [Troubleshooting](docs/troubleshooting.md)
|
||||||
|
|
||||||
### Decentralized Identity
|
## Quick start
|
||||||
- Ed25519 node identity with DID Documents (did:key)
|
|
||||||
- Multi-identity management (Personal/Business/Anonymous)
|
|
||||||
- W3C Verifiable Credentials issuance and verification
|
|
||||||
- Nostr integration: NIP-33 node discovery, NIP-44/NIP-04 encryption, NIP-07 signer bridge for iframe apps, relay hosting
|
|
||||||
- Decentralized Web Node (DWN) record sync between federated nodes over Tor
|
|
||||||
|
|
||||||
### Multi-Node Federation
|
### Frontend
|
||||||
- Invite-based node joining over Tor hidden services
|
|
||||||
- Trust levels (Trusted/Verified/Untrusted) with DID-based auth
|
|
||||||
- State sync and app deployment across federated nodes
|
|
||||||
- File sharing with access controls (free/peers-only/paid via Lightning, on-chain, or ecash)
|
|
||||||
|
|
||||||
### System Updates
|
|
||||||
- OTA updates from a self-hosted Gitea release server, Ed25519-signature-verified against a pinned release-root key
|
|
||||||
- Resumable downloads, automatic pre-update backup, rollback with a post-update self-verify window
|
|
||||||
- Manual, scheduled-check, and auto-apply modes (auto-apply refuses unsigned manifests)
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- Argon2id password hashing (transparent upgrade from legacy hashes), ChaCha20-Poly1305 encrypted secrets at rest
|
|
||||||
- Rootless Podman: read-only root, cap-drop ALL with a reviewed allow-list, no-new-privileges
|
|
||||||
- Signed release manifests and signed app catalog (Ed25519, pinned trust anchor)
|
|
||||||
- TOTP two-factor authentication, per-endpoint rate limiting, CSRF protection
|
|
||||||
- AppArmor profiles for container confinement; Tor hidden services for inter-node traffic
|
|
||||||
- Independent security audit of an early version archived in [`docs/archive/`](docs/archive/security-code-audit-2026-03.md); top findings since remediated
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
|
|
||||||
**Done**
|
|
||||||
- Single-node production gate **green** — install / stop / start / restart / reinstall / reboot-survive / uninstall, 5 consecutive full runs with zero failures on real hardware
|
|
||||||
- Quadlet migration validated (all backends as `user.slice` services on the canary node)
|
|
||||||
- Release signing ceremony completed — release-root key pinned, catalog and OTA manifests signed
|
|
||||||
- Reticulum third mesh transport (real-RF LoRa gates passed), Bitcoin Core/Knots multi-version switching, decentralized marketplace backend, public demo
|
|
||||||
|
|
||||||
**In progress**
|
|
||||||
- Multinode pass: the same production gate across the whole test fleet ([`docs/multinode-testing-plan.md`](docs/multinode-testing-plan.md))
|
|
||||||
- Quadlet default flip fleet-wide + container-flapping elimination
|
|
||||||
- 1.8.0 release hardening tail ([`docs/1.8.0-RELEASE-HARDENING-PLAN.md`](docs/1.8.0-RELEASE-HARDENING-PLAN.md)): OTA upgrade soak on real hardware, ISO/image hardening (per-device keys, no default creds, signed ISO)
|
|
||||||
|
|
||||||
**Planned**
|
|
||||||
- Developer CLI (`archy app validate/render/install/test`) to open third-party app publishing
|
|
||||||
- External marketplace trust UX + publishing tooling ([`docs/marketplace-protocol.md`](docs/marketplace-protocol.md))
|
|
||||||
- DHT/P2P distribution of releases and app images ([`docs/dht-distribution-design.md`](docs/dht-distribution-design.md))
|
|
||||||
- P2P encrypted voice/video over Tor, dual-ecash (Fedimint + Cashu) phases, paid streaming, hardware signer support
|
|
||||||
|
|
||||||
The live, priority-ordered task list is [`docs/UNIFIED-TASK-TRACKER.md`](docs/UNIFIED-TASK-TRACKER.md); the full narrative plan is [`docs/PRODUCTION-MASTER-PLAN.md`](docs/PRODUCTION-MASTER-PLAN.md).
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### Install from ISO
|
|
||||||
|
|
||||||
1. Build or download the ISO for your architecture (x86_64 or ARM64) — see [`image-recipe/`](image-recipe/)
|
|
||||||
2. Flash to USB drive with Balena Etcher or `dd`
|
|
||||||
3. Boot from USB on target hardware and follow the automated installer
|
|
||||||
4. Access the web UI at `http://<device-ip>`
|
|
||||||
5. Set your password and complete the onboarding wizard (seed backup, DID identity)
|
|
||||||
|
|
||||||
### Supported Hardware
|
|
||||||
|
|
||||||
| Platform | Examples | Minimum |
|
|
||||||
|----------|----------|---------|
|
|
||||||
| **x86_64** | Intel NUC, mini PCs, any 64-bit PC | 4GB RAM, 32GB storage |
|
|
||||||
| **ARM64** | Raspberry Pi 5, ARM64 SBCs | 4GB RAM, 32GB storage |
|
|
||||||
|
|
||||||
**Recommended**: 8GB+ RAM, 1TB+ NVMe SSD (for a full Bitcoin node). Optional: an RNode-compatible LoRa radio for mesh networking.
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
- macOS or Linux for frontend development
|
|
||||||
- Linux dev server (Debian 13) for backend builds — **never build Rust on macOS for Linux**
|
|
||||||
- Node.js 20+, Rust stable toolchain
|
|
||||||
|
|
||||||
### Frontend Development
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd neode-ui
|
cd neode-ui
|
||||||
npm install
|
npm install
|
||||||
npm start # Dev server on http://localhost:8100 (mock backend on :5959)
|
npm start
|
||||||
npm run type-check # TypeScript validation
|
|
||||||
npm run build # Production build → web/dist/neode-ui/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backend Development
|
The dev UI runs at `http://localhost:8100` with a mock backend on `:5959`.
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd core # Rust workspace root (no Cargo.toml at repo root)
|
cd core
|
||||||
cargo build
|
cargo build
|
||||||
cargo test
|
cargo test --all-features
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deploy to a Test Node
|
Linux is the supported backend runtime and release-build target. macOS is fine
|
||||||
|
for frontend work and many Rust compile/test loops, but host integration tests
|
||||||
|
that touch Podman, systemd, networking, or image build paths require Linux.
|
||||||
|
|
||||||
|
### App manifests
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/deploy-to-target.sh --live # Deploy to primary dev server
|
./scripts/validate-app-manifest.sh apps/filebrowser/manifest.yml
|
||||||
./scripts/deploy-to-target.sh --both # Deploy to both LAN servers
|
python3 scripts/generate-app-catalog.py
|
||||||
|
python3 scripts/check-app-catalog-drift.py --release --strict
|
||||||
```
|
```
|
||||||
|
|
||||||
### Release (tarball-only)
|
`scripts/generate-app-catalog.py` requires Python with PyYAML installed.
|
||||||
|
|
||||||
Releases ship as a backend binary and a frontend tarball referenced by
|
## Documentation map
|
||||||
`releases/manifest.json`, published to the self-hosted Gitea release server.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/create-release.sh 1.2.3
|
|
||||||
git push origin main --tags
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Debian 13 (Trixie)
|
|
||||||
├── Rootless Podman — every app a systemd Quadlet unit under user.slice
|
|
||||||
├── Nginx (reverse proxy, security headers, rate limiting)
|
|
||||||
├── Rust Backend (JSON-RPC API on 127.0.0.1:5678, ~380 RPC methods)
|
|
||||||
│ ├── core/archipelago/ — API, orchestrator + reconciler, mesh, identity,
|
|
||||||
│ │ federation, wallet, updates, marketplace
|
|
||||||
│ ├── core/container/ — Podman client, manifest schema, Quadlet compiler,
|
|
||||||
│ │ health monitor, signed app catalog
|
|
||||||
│ ├── core/security/ — AppArmor/seccomp policy, secrets manager
|
|
||||||
│ ├── core/openwrt/ — TollGate gateway provisioning (SSH/UCI)
|
|
||||||
│ └── core/performance/ — resource limits
|
|
||||||
├── Vue 3 Frontend (Composition API + TypeScript strict + Pinia + Tailwind, PWA)
|
|
||||||
│ └── Three UI modes (Pro/Easy/Chat) + gamepad navigation + i18n
|
|
||||||
├── Reticulum daemon (supervised Python/PyInstaller, one per LoRa radio)
|
|
||||||
└── System Tor (hidden services, SOCKS5 proxy)
|
|
||||||
```
|
|
||||||
|
|
||||||
~117,000 lines of Rust | ~69,000 lines of TypeScript/Vue | 51 packaged apps | Android companion app
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
| Doc | Purpose |
|
| Doc | Purpose |
|
||||||
|-----|---------|
|
|-----|---------|
|
||||||
| [Architecture](docs/architecture.md) | System design, crate map, data paths |
|
| [Architecture](docs/architecture.md) | System layers, crates, data paths, security model |
|
||||||
| [Developer Guide](docs/developer-guide.md) | Dev setup, workflow, code conventions |
|
| [Developer Guide](docs/developer-guide.md) | Local setup, code workflow, testing |
|
||||||
| [API Reference](docs/api-reference.md) | RPC endpoint reference |
|
| [API Reference](docs/api-reference.md) | JSON-RPC API overview |
|
||||||
| [App Developer Guide](docs/app-developer-guide.md) | Building and publishing apps |
|
| [App Developer Guide](docs/app-developer-guide.md) | How to package and test apps |
|
||||||
| [App Manifest Spec](docs/app-manifest-spec.md) | The `manifest.yml` schema |
|
| [App Manifest Spec](docs/app-manifest-spec.md) | Manifest schema and validation rules |
|
||||||
| [User Walkthrough](docs/user-walkthrough.md) | End-user installation and usage guide |
|
| [Nostr Git Source Hosting Plan](docs/nostr-git-source-hosting.md) | ngit/NIP-34 contribution workflow and maintainer model |
|
||||||
| [Troubleshooting](docs/troubleshooting.md) | Diagnostic scenarios and solutions |
|
| [Apps README](apps/README.md) | Packaged app catalog overview |
|
||||||
| [Operations Runbook](docs/operations-runbook.md) | Ops commands and emergency recovery |
|
| [Image Recipe](image-recipe/README.md) | Bootable image build flow |
|
||||||
| [Production Master Plan](docs/PRODUCTION-MASTER-PLAN.md) | North star and workstream narrative |
|
| [Operations Runbook](docs/operations-runbook.md) | Production operations and recovery |
|
||||||
| [Unified Task Tracker](docs/UNIFIED-TASK-TRACKER.md) | Live, priority-ordered open items |
|
| [Open Source Readiness](docs/OPEN_SOURCE_READINESS.md) | Public-release cleanup checklist |
|
||||||
| [Test Gate](tests/lifecycle/TESTING.md) | Production lifecycle test gate (definition of done) |
|
| [Roadmap](docs/ROADMAP.md) | Shipped, in-progress, and planned work |
|
||||||
| [Archive](docs/archive/) | Historical audits, session logs, shipped designs |
|
| [Unified Task Tracker](docs/UNIFIED-TASK-TRACKER.md) | Launch hardening task list |
|
||||||
|
| [Archive](docs/archive/) | Historical plans, audits, and handoffs |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. Fork the repository
|
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. For
|
||||||
2. Create a feature branch (`feature/description`)
|
security issues, follow [SECURITY.md](SECURITY.md) and do not open a public
|
||||||
3. Follow the coding standards in [CONTRIBUTING.md](CONTRIBUTING.md) and [CLAUDE.md](CLAUDE.md)
|
issue.
|
||||||
4. Submit a pull request
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT License](LICENSE)
|
Archipelago is licensed under the [MIT License](LICENSE). Third-party notices
|
||||||
|
are listed in [NOTICE](NOTICE) and generated license inventories in component
|
||||||
## Acknowledgments
|
release artifacts.
|
||||||
|
|
||||||
Built with: [Rust](https://www.rust-lang.org/), [Vue.js](https://vuejs.org/), [Podman](https://podman.io/), [Bitcoin Core](https://bitcoin.org/), [LND](https://lightning.engineering/), [Reticulum](https://reticulum.network/), [Debian](https://www.debian.org/)
|
|
||||||
|
|||||||
38
SECURITY.md
Normal file
38
SECURITY.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting vulnerabilities
|
||||||
|
|
||||||
|
Please do not open a public issue for a security vulnerability.
|
||||||
|
|
||||||
|
Until a dedicated security intake address is published, report privately to the
|
||||||
|
project maintainer through the repository owner account or the private contact
|
||||||
|
channel listed on the project homepage.
|
||||||
|
|
||||||
|
Include:
|
||||||
|
|
||||||
|
- affected commit, version, or release;
|
||||||
|
- affected component;
|
||||||
|
- reproduction steps;
|
||||||
|
- expected impact;
|
||||||
|
- logs, proof of concept, or packet captures when relevant;
|
||||||
|
- whether the issue is already public.
|
||||||
|
|
||||||
|
We aim to acknowledge credible reports within 48 hours and coordinate fixes
|
||||||
|
before public disclosure.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Security-sensitive areas include:
|
||||||
|
|
||||||
|
- authentication, session handling, CSRF, and rate limiting;
|
||||||
|
- release and app-catalog signature verification;
|
||||||
|
- container manifest validation and runtime compilation;
|
||||||
|
- Podman/Quadlet isolation, capabilities, volumes, and secret injection;
|
||||||
|
- backup encryption and key derivation;
|
||||||
|
- federation, Tor, Nostr, mesh, DID, and credential flows;
|
||||||
|
- Android companion pairing and device-token handling.
|
||||||
|
|
||||||
|
## Supported versions
|
||||||
|
|
||||||
|
Archipelago is currently pre-1.0 alpha software. Security fixes target the
|
||||||
|
current `main` branch and the latest published alpha release.
|
||||||
@ -76,7 +76,17 @@ podman run -p 18084:8080 \
|
|||||||
|
|
||||||
## Integration Checklist
|
## Integration Checklist
|
||||||
|
|
||||||
Adding a new app requires updates in multiple places. See the full checklist in [CLAUDE.md](../CLAUDE.md) under "App Integration Checklist".
|
Adding a new app requires updates in multiple places:
|
||||||
|
|
||||||
|
- add `apps/<app-id>/manifest.yml`;
|
||||||
|
- add a Dockerfile and source directory only when the app is built locally;
|
||||||
|
- choose non-conflicting ports from [PORTS.md](./PORTS.md);
|
||||||
|
- declare `interfaces.main` for user-facing web UIs;
|
||||||
|
- declare generated secrets instead of hardcoding credentials;
|
||||||
|
- run `./scripts/validate-app-manifest.sh apps/<app-id>/manifest.yml`;
|
||||||
|
- regenerate catalogs with `python3 scripts/generate-app-catalog.py`;
|
||||||
|
- verify drift with `python3 scripts/check-app-catalog-drift.py --release --strict`;
|
||||||
|
- test install, launch, stop, start, restart, uninstall, and reinstall.
|
||||||
|
|
||||||
## Port Assignments
|
## Port Assignments
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
# Archipelago Production Configuration
|
|
||||||
# This file is bundled with the macOS app
|
|
||||||
|
|
||||||
# Server Configuration
|
|
||||||
ARCHIPELAGO_HOST=127.0.0.1
|
|
||||||
ARCHIPELAGO_PORT=8100
|
|
||||||
ARCHIPELAGO_BACKEND_PORT=3030
|
|
||||||
|
|
||||||
# Data Directories (relative to ~/Library/Application Support/Archipelago)
|
|
||||||
ARCHIPELAGO_DATA_DIR=data
|
|
||||||
ARCHIPELAGO_LOG_DIR=logs
|
|
||||||
|
|
||||||
# Frontend Configuration
|
|
||||||
ARCHIPELAGO_FRONTEND_DIR=frontend
|
|
||||||
|
|
||||||
# Docker UI Configuration
|
|
||||||
ARCHIPELAGO_DOCKER_UI_DIR=docker-ui
|
|
||||||
|
|
||||||
# Security
|
|
||||||
ARCHIPELAGO_SESSION_SECRET=CHANGE_ME_ON_FIRST_RUN
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
RUST_LOG=info
|
|
||||||
|
|
||||||
# Production Mode
|
|
||||||
NODE_ENV=production
|
|
||||||
ARCHIPELAGO_MODE=production
|
|
||||||
|
|
||||||
# Docker Configuration
|
|
||||||
DOCKER_HOST=unix:///var/run/docker.sock
|
|
||||||
|
|
||||||
# Disable External API Calls in Production
|
|
||||||
ARCHIPELAGO_DISABLE_EXTERNAL_APIS=true
|
|
||||||
656
core/THIRD-PARTY-LICENSES.md
Normal file
656
core/THIRD-PARTY-LICENSES.md
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
# Third-Party Rust Crate Licenses — Archipelago core
|
||||||
|
|
||||||
|
Generated from `cargo metadata` (all features) on 2026-07-23. 649 external crates.
|
||||||
|
Full license texts ship with release artifacts (cargo-about; see docs/LICENSE-COMPLIANCE-AUDIT.md).
|
||||||
|
|
||||||
|
| Crate | Version | License | Source |
|
||||||
|
|---|---|---|---|
|
||||||
|
| adler2 | 2.0.1 | 0BSD OR MIT OR Apache-2.0 | https://github.com/oyvindln/adler2 |
|
||||||
|
| aead | 0.5.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| aes | 0.8.4 | MIT OR Apache-2.0 | https://github.com/RustCrypto/block-ciphers |
|
||||||
|
| aes-gcm | 0.10.3 | Apache-2.0 OR MIT | https://github.com/RustCrypto/AEADs |
|
||||||
|
| ahash | 0.7.8 | MIT OR Apache-2.0 | https://github.com/tkaitchuck/ahash |
|
||||||
|
| aho-corasick | 1.1.4 | Unlicense OR MIT | https://github.com/BurntSushi/aho-corasick |
|
||||||
|
| allocator-api2 | 0.2.21 | MIT OR Apache-2.0 | https://github.com/zakarumych/allocator-api2 |
|
||||||
|
| android_system_properties | 0.1.5 | MIT/Apache-2.0 | https://github.com/nical/android_system_properties |
|
||||||
|
| anyhow | 1.0.100 | MIT OR Apache-2.0 | https://github.com/dtolnay/anyhow |
|
||||||
|
| arc-swap | 1.9.1 | MIT OR Apache-2.0 | https://github.com/vorner/arc-swap |
|
||||||
|
| argon2 | 0.5.3 | MIT OR Apache-2.0 | https://github.com/RustCrypto/password-hashes/tree/master/argon2 |
|
||||||
|
| arrayref | 0.3.9 | BSD-2-Clause | https://github.com/droundy/arrayref |
|
||||||
|
| arrayvec | 0.7.6 | MIT OR Apache-2.0 | https://github.com/bluss/arrayvec |
|
||||||
|
| asn1-rs | 0.7.2 | MIT OR Apache-2.0 | https://github.com/rusticata/asn1-rs.git |
|
||||||
|
| asn1-rs-derive | 0.6.0 | MIT OR Apache-2.0 | https://github.com/rusticata/asn1-rs.git |
|
||||||
|
| asn1-rs-impl | 0.2.0 | MIT/Apache-2.0 | https://github.com/rusticata/asn1-rs.git |
|
||||||
|
| async-trait | 0.1.89 | MIT OR Apache-2.0 | https://github.com/dtolnay/async-trait |
|
||||||
|
| async-utility | 0.3.1 | MIT | https://github.com/yukibtc/async-utility.git |
|
||||||
|
| async-wsocket | 0.13.1 | MIT | https://github.com/yukibtc/async-wsocket.git |
|
||||||
|
| async_io_stream | 0.3.3 | Unlicense | https://github.com/najamelan/async_io_stream |
|
||||||
|
| atomic-destructor | 0.3.0 | MIT | https://github.com/yukibtc/atomic-destructor.git |
|
||||||
|
| atomic-polyfill | 1.0.3 | MIT OR Apache-2.0 | https://github.com/embassy-rs/atomic-polyfill |
|
||||||
|
| atomic-waker | 1.1.2 | Apache-2.0 OR MIT | https://github.com/smol-rs/atomic-waker |
|
||||||
|
| attohttpc | 0.30.1 | MPL-2.0 | https://github.com/sbstp/attohttpc |
|
||||||
|
| autocfg | 1.5.0 | Apache-2.0 OR MIT | https://github.com/cuviper/autocfg |
|
||||||
|
| backon | 1.6.0 | Apache-2.0 | https://github.com/Xuanwo/backon |
|
||||||
|
| bao-tree | 0.16.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/bao-tree |
|
||||||
|
| base16ct | 1.0.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| base32 | 0.5.1 | MIT OR Apache-2.0 | https://github.com/andreasots/base32 |
|
||||||
|
| base58ck | 0.1.0 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin/ |
|
||||||
|
| base64 | 0.21.7 | MIT OR Apache-2.0 | https://github.com/marshallpierce/rust-base64 |
|
||||||
|
| base64 | 0.22.1 | MIT OR Apache-2.0 | https://github.com/marshallpierce/rust-base64 |
|
||||||
|
| base64ct | 1.8.3 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| bcrypt | 0.15.1 | MIT | https://github.com/Keats/rust-bcrypt |
|
||||||
|
| bech32 | 0.11.1 | MIT | https://github.com/rust-bitcoin/rust-bech32 |
|
||||||
|
| binary-merge | 0.1.2 | MIT OR Apache-2.0 | https://github.com/rklaehn/binary-merge |
|
||||||
|
| bip39 | 2.1.0 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bip39/ |
|
||||||
|
| bit-vec | 0.9.1 | Apache-2.0 OR MIT | https://github.com/contain-rs/bit-vec |
|
||||||
|
| bitcoin | 0.32.5 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin/ |
|
||||||
|
| bitcoin-internals | 0.2.0 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin/ |
|
||||||
|
| bitcoin-internals | 0.3.0 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin/ |
|
||||||
|
| bitcoin-io | 0.1.4 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin |
|
||||||
|
| bitcoin-units | 0.1.2 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin/ |
|
||||||
|
| bitcoin_hashes | 0.13.0 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin |
|
||||||
|
| bitcoin_hashes | 0.14.1 | CC0-1.0 | https://github.com/rust-bitcoin/rust-bitcoin |
|
||||||
|
| bitflags | 1.3.2 | MIT/Apache-2.0 | https://github.com/bitflags/bitflags |
|
||||||
|
| bitflags | 2.13.0 | MIT OR Apache-2.0 | https://github.com/bitflags/bitflags |
|
||||||
|
| blake2 | 0.10.6 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hashes |
|
||||||
|
| blake3 | 1.8.5 | CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception | https://github.com/BLAKE3-team/BLAKE3 |
|
||||||
|
| block-buffer | 0.10.4 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| block-buffer | 0.12.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| block-padding | 0.3.3 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| block2 | 0.6.2 | MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| blowfish | 0.9.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/block-ciphers |
|
||||||
|
| bs58 | 0.5.1 | MIT/Apache-2.0 | https://github.com/Nullus157/bs58-rs |
|
||||||
|
| bumpalo | 3.19.1 | MIT OR Apache-2.0 | https://github.com/fitzgen/bumpalo |
|
||||||
|
| bytemuck | 1.25.0 | Zlib OR Apache-2.0 OR MIT | https://github.com/Lokathor/bytemuck |
|
||||||
|
| byteorder | 1.5.0 | Unlicense OR MIT | https://github.com/BurntSushi/byteorder |
|
||||||
|
| byteorder-lite | 0.1.0 | Unlicense OR MIT | https://github.com/image-rs/byteorder-lite |
|
||||||
|
| bytes | 1.11.0 | MIT | https://github.com/tokio-rs/bytes |
|
||||||
|
| cbc | 0.1.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/block-modes |
|
||||||
|
| cc | 1.2.54 | MIT OR Apache-2.0 | https://github.com/rust-lang/cc-rs |
|
||||||
|
| cesu8 | 1.1.0 | Apache-2.0/MIT | https://github.com/emk/cesu8-rs |
|
||||||
|
| cfg-if | 1.0.4 | MIT OR Apache-2.0 | https://github.com/rust-lang/cfg-if |
|
||||||
|
| cfg_aliases | 0.2.1 | MIT | https://github.com/katharostech/cfg_aliases |
|
||||||
|
| chacha20 | 0.10.0 | MIT OR Apache-2.0 | https://github.com/RustCrypto/stream-ciphers |
|
||||||
|
| chacha20 | 0.9.1 | Apache-2.0 OR MIT | https://github.com/RustCrypto/stream-ciphers |
|
||||||
|
| chacha20poly1305 | 0.10.1 | Apache-2.0 OR MIT | https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305 |
|
||||||
|
| chrono | 0.4.43 | MIT OR Apache-2.0 | https://github.com/chronotope/chrono |
|
||||||
|
| ciborium | 0.2.2 | Apache-2.0 | https://github.com/enarx/ciborium |
|
||||||
|
| ciborium-io | 0.2.2 | Apache-2.0 | https://github.com/enarx/ciborium |
|
||||||
|
| ciborium-ll | 0.2.2 | Apache-2.0 | https://github.com/enarx/ciborium |
|
||||||
|
| cipher | 0.4.4 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| cmov | 0.5.4 | Apache-2.0 OR MIT | https://github.com/RustCrypto/utils |
|
||||||
|
| cobs | 0.3.0 | MIT OR Apache-2.0 | https://github.com/jamesmunns/cobs.rs |
|
||||||
|
| combine | 4.6.7 | MIT | https://github.com/Marwes/combine |
|
||||||
|
| const-oid | 0.10.2 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| const-oid | 0.9.6 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats/tree/master/const-oid |
|
||||||
|
| constant_time_eq | 0.3.1 | CC0-1.0 OR MIT-0 OR Apache-2.0 | https://github.com/cesarb/constant_time_eq |
|
||||||
|
| constant_time_eq | 0.4.2 | CC0-1.0 OR MIT-0 OR Apache-2.0 | https://github.com/cesarb/constant_time_eq |
|
||||||
|
| convert_case | 0.10.0 | MIT | https://github.com/rutrum/convert-case |
|
||||||
|
| cordyceps | 0.3.4 | MIT | https://github.com/hawkw/mycelium |
|
||||||
|
| core-foundation | 0.10.1 | MIT OR Apache-2.0 | https://github.com/servo/core-foundation-rs |
|
||||||
|
| core-foundation | 0.9.4 | MIT OR Apache-2.0 | https://github.com/servo/core-foundation-rs |
|
||||||
|
| core-foundation-sys | 0.8.7 | MIT OR Apache-2.0 | https://github.com/servo/core-foundation-rs |
|
||||||
|
| cpufeatures | 0.2.17 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| cpufeatures | 0.3.0 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| crc | 3.4.0 | MIT OR Apache-2.0 | https://github.com/mrhooray/crc-rs.git |
|
||||||
|
| crc-catalog | 2.4.0 | MIT OR Apache-2.0 | https://github.com/akhilles/crc-catalog.git |
|
||||||
|
| crc32fast | 1.5.0 | MIT OR Apache-2.0 | https://github.com/srijs/rust-crc32fast |
|
||||||
|
| critical-section | 1.2.0 | MIT OR Apache-2.0 | https://github.com/rust-embedded/critical-section |
|
||||||
|
| crossbeam-channel | 0.5.15 | MIT OR Apache-2.0 | https://github.com/crossbeam-rs/crossbeam |
|
||||||
|
| crossbeam-epoch | 0.9.18 | MIT OR Apache-2.0 | https://github.com/crossbeam-rs/crossbeam |
|
||||||
|
| crossbeam-utils | 0.8.21 | MIT OR Apache-2.0 | https://github.com/crossbeam-rs/crossbeam |
|
||||||
|
| crunchy | 0.2.4 | MIT | https://github.com/eira-fransham/crunchy |
|
||||||
|
| crypto-common | 0.1.7 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| crypto-common | 0.2.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| ctr | 0.9.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/block-modes |
|
||||||
|
| ctutils | 0.4.2 | Apache-2.0 OR MIT | https://github.com/RustCrypto/utils |
|
||||||
|
| curve25519-dalek | 4.1.3 | BSD-3-Clause | https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek |
|
||||||
|
| curve25519-dalek | 5.0.0-rc.0 | BSD-3-Clause | https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek |
|
||||||
|
| curve25519-dalek-derive | 0.1.1 | MIT/Apache-2.0 | https://github.com/dalek-cryptography/curve25519-dalek |
|
||||||
|
| darling | 0.20.11 | MIT | https://github.com/TedDriggs/darling |
|
||||||
|
| darling_core | 0.20.11 | MIT | https://github.com/TedDriggs/darling |
|
||||||
|
| darling_macro | 0.20.11 | MIT | https://github.com/TedDriggs/darling |
|
||||||
|
| data-encoding | 2.11.0 | MIT | https://github.com/ia0/data-encoding |
|
||||||
|
| data-encoding-macro | 0.1.20 | MIT | https://github.com/ia0/data-encoding |
|
||||||
|
| data-encoding-macro-internal | 0.1.18 | MIT | https://github.com/ia0/data-encoding |
|
||||||
|
| der | 0.7.10 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats/tree/master/der |
|
||||||
|
| der | 0.8.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| der-parser | 10.0.0 | MIT OR Apache-2.0 | https://github.com/rusticata/der-parser.git |
|
||||||
|
| deranged | 0.5.8 | MIT OR Apache-2.0 | https://github.com/jhpratt/deranged |
|
||||||
|
| derive_builder | 0.20.2 | MIT OR Apache-2.0 | https://github.com/colin-kiegel/rust-derive-builder |
|
||||||
|
| derive_builder_core | 0.20.2 | MIT OR Apache-2.0 | https://github.com/colin-kiegel/rust-derive-builder |
|
||||||
|
| derive_builder_macro | 0.20.2 | MIT OR Apache-2.0 | https://github.com/colin-kiegel/rust-derive-builder |
|
||||||
|
| derive_more | 2.1.1 | MIT | https://github.com/JelteF/derive_more |
|
||||||
|
| derive_more-impl | 2.1.1 | MIT | https://github.com/JelteF/derive_more |
|
||||||
|
| diatomic-waker | 0.2.3 | MIT OR Apache-2.0 | https://github.com/asynchronics/diatomic-waker |
|
||||||
|
| digest | 0.10.7 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| digest | 0.11.3 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| dispatch2 | 0.3.1 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| displaydoc | 0.2.5 | MIT OR Apache-2.0 | https://github.com/yaahc/displaydoc |
|
||||||
|
| dlopen2 | 0.8.2 | MIT | https://github.com/OpenByteDev/dlopen2 |
|
||||||
|
| ed25519 | 2.2.3 | Apache-2.0 OR MIT | https://github.com/RustCrypto/signatures/tree/master/ed25519 |
|
||||||
|
| ed25519 | 3.0.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/signatures |
|
||||||
|
| ed25519-dalek | 2.2.0 | BSD-3-Clause | https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek |
|
||||||
|
| ed25519-dalek | 3.0.0-rc.0 | BSD-3-Clause | https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek |
|
||||||
|
| either | 1.15.0 | MIT OR Apache-2.0 | https://github.com/rayon-rs/either |
|
||||||
|
| embedded-io | 0.4.0 | MIT OR Apache-2.0 | https://github.com/embassy-rs/embedded-io |
|
||||||
|
| embedded-io | 0.6.1 | MIT OR Apache-2.0 | https://github.com/rust-embedded/embedded-hal |
|
||||||
|
| encoding_rs | 0.8.35 | (Apache-2.0 OR MIT) AND BSD-3-Clause | https://github.com/hsivonen/encoding_rs |
|
||||||
|
| enum-assoc | 1.3.0 | MIT OR Apache-2.0 | https://github.com/Eolu/enum-assoc |
|
||||||
|
| env_logger | 0.10.2 | MIT OR Apache-2.0 | https://github.com/rust-cli/env_logger |
|
||||||
|
| equivalent | 1.0.2 | Apache-2.0 OR MIT | https://github.com/indexmap-rs/equivalent |
|
||||||
|
| errno | 0.3.14 | MIT OR Apache-2.0 | https://github.com/lambda-fairy/rust-errno |
|
||||||
|
| fastbloom | 0.17.0 | MIT OR Apache-2.0 | https://github.com/tomtomwombat/fastbloom/ |
|
||||||
|
| fastrand | 2.3.0 | Apache-2.0 OR MIT | https://github.com/smol-rs/fastrand |
|
||||||
|
| fiat-crypto | 0.2.9 | MIT OR Apache-2.0 OR BSD-1-Clause | https://github.com/mit-plv/fiat-crypto |
|
||||||
|
| fiat-crypto | 0.3.0 | MIT OR Apache-2.0 OR BSD-1-Clause | https://github.com/mit-plv/fiat-crypto |
|
||||||
|
| filetime | 0.2.27 | MIT/Apache-2.0 | https://github.com/alexcrichton/filetime |
|
||||||
|
| find-msvc-tools | 0.1.8 | MIT OR Apache-2.0 | https://github.com/rust-lang/cc-rs |
|
||||||
|
| flate2 | 1.1.9 | MIT OR Apache-2.0 | https://github.com/rust-lang/flate2-rs |
|
||||||
|
| flume | 0.11.1 | Apache-2.0/MIT | https://github.com/zesterer/flume |
|
||||||
|
| fnv | 1.0.7 | Apache-2.0 / MIT | https://github.com/servo/rust-fnv |
|
||||||
|
| foldhash | 0.1.5 | Zlib | https://github.com/orlp/foldhash |
|
||||||
|
| foldhash | 0.2.0 | Zlib | https://github.com/orlp/foldhash |
|
||||||
|
| form_urlencoded | 1.2.2 | MIT OR Apache-2.0 | https://github.com/servo/rust-url |
|
||||||
|
| futures | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-buffered | 0.2.13 | MIT | https://github.com/conradludgate/futures-buffered |
|
||||||
|
| futures-channel | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-core | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-executor | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-io | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-lite | 2.6.1 | Apache-2.0 OR MIT | https://github.com/smol-rs/futures-lite |
|
||||||
|
| futures-macro | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-sink | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-task | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| futures-util | 0.3.31 | MIT OR Apache-2.0 | https://github.com/rust-lang/futures-rs |
|
||||||
|
| genawaiter | 0.99.1 | MIT | https://github.com/whatisaphone/genawaiter |
|
||||||
|
| genawaiter-macro | 0.99.1 | MIT/Apache-2.0 | https://github.com/whatisaphone/genawaiter |
|
||||||
|
| genawaiter-proc-macro | 0.99.1 | MIT/Apache-2.0 | https://github.com/whatisaphone/genawaiter |
|
||||||
|
| generator | 0.8.9 | MIT/Apache-2.0 | https://github.com/Xudong-Huang/generator-rs.git |
|
||||||
|
| generic-array | 0.14.7 | MIT | https://github.com/fizyk20/generic-array.git |
|
||||||
|
| getrandom | 0.2.17 | MIT OR Apache-2.0 | https://github.com/rust-random/getrandom |
|
||||||
|
| getrandom | 0.3.4 | MIT OR Apache-2.0 | https://github.com/rust-random/getrandom |
|
||||||
|
| getrandom | 0.4.2 | MIT OR Apache-2.0 | https://github.com/rust-random/getrandom |
|
||||||
|
| ghash | 0.5.1 | Apache-2.0 OR MIT | https://github.com/RustCrypto/universal-hashes |
|
||||||
|
| gloo-timers | 0.3.0 | MIT OR Apache-2.0 | https://github.com/rustwasm/gloo/tree/master/crates/timers |
|
||||||
|
| h2 | 0.3.27 | MIT | https://github.com/hyperium/h2 |
|
||||||
|
| h2 | 0.4.13 | MIT | https://github.com/hyperium/h2 |
|
||||||
|
| half | 2.7.1 | MIT OR Apache-2.0 | https://github.com/VoidStarKat/half-rs |
|
||||||
|
| hash32 | 0.2.1 | MIT OR Apache-2.0 | https://github.com/japaric/hash32 |
|
||||||
|
| hashbrown | 0.12.3 | MIT OR Apache-2.0 | https://github.com/rust-lang/hashbrown |
|
||||||
|
| hashbrown | 0.15.5 | MIT OR Apache-2.0 | https://github.com/rust-lang/hashbrown |
|
||||||
|
| hashbrown | 0.16.1 | MIT OR Apache-2.0 | https://github.com/rust-lang/hashbrown |
|
||||||
|
| hashbrown | 0.17.1 | MIT OR Apache-2.0 | https://github.com/rust-lang/hashbrown |
|
||||||
|
| heapless | 0.7.17 | MIT OR Apache-2.0 | https://github.com/japaric/heapless |
|
||||||
|
| heck | 0.5.0 | MIT OR Apache-2.0 | https://github.com/withoutboats/heck |
|
||||||
|
| hermit-abi | 0.5.2 | MIT OR Apache-2.0 | https://github.com/hermit-os/hermit-rs |
|
||||||
|
| hex | 0.4.3 | MIT OR Apache-2.0 | https://github.com/KokaKiwi/rust-hex |
|
||||||
|
| hex-conservative | 0.1.2 | CC0-1.0 | https://github.com/rust-bitcoin/hex-conservative |
|
||||||
|
| hex-conservative | 0.2.2 | CC0-1.0 | https://github.com/rust-bitcoin/hex-conservative |
|
||||||
|
| hex_lit | 0.1.1 | MITNFA | https://github.com/Kixunil/hex_lit |
|
||||||
|
| hickory-net | 0.26.1 | MIT OR Apache-2.0 | https://github.com/hickory-dns/hickory-dns |
|
||||||
|
| hickory-proto | 0.26.1 | MIT OR Apache-2.0 | https://github.com/hickory-dns/hickory-dns |
|
||||||
|
| hickory-resolver | 0.26.1 | MIT OR Apache-2.0 | https://github.com/hickory-dns/hickory-dns |
|
||||||
|
| hkdf | 0.12.4 | MIT OR Apache-2.0 | https://github.com/RustCrypto/KDFs/ |
|
||||||
|
| hmac | 0.12.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/MACs |
|
||||||
|
| http | 0.2.12 | MIT OR Apache-2.0 | https://github.com/hyperium/http |
|
||||||
|
| http | 1.4.0 | MIT OR Apache-2.0 | https://github.com/hyperium/http |
|
||||||
|
| http-body | 0.4.6 | MIT | https://github.com/hyperium/http-body |
|
||||||
|
| http-body | 1.0.1 | MIT | https://github.com/hyperium/http-body |
|
||||||
|
| http-body-util | 0.1.3 | MIT | https://github.com/hyperium/http-body |
|
||||||
|
| httparse | 1.10.1 | MIT OR Apache-2.0 | https://github.com/seanmonstar/httparse |
|
||||||
|
| httpdate | 1.0.3 | MIT OR Apache-2.0 | https://github.com/pyfisch/httpdate |
|
||||||
|
| humantime | 2.3.0 | MIT OR Apache-2.0 | https://github.com/chronotope/humantime |
|
||||||
|
| hybrid-array | 0.4.12 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hybrid-array |
|
||||||
|
| hyper | 0.14.32 | MIT | https://github.com/hyperium/hyper |
|
||||||
|
| hyper | 1.8.1 | MIT | https://github.com/hyperium/hyper |
|
||||||
|
| hyper-rustls | 0.24.2 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/hyper-rustls |
|
||||||
|
| hyper-rustls | 0.27.9 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/hyper-rustls |
|
||||||
|
| hyper-util | 0.1.19 | MIT | https://github.com/hyperium/hyper-util |
|
||||||
|
| hyper-ws-listener | 0.3.0 | MIT | |
|
||||||
|
| iana-time-zone | 0.1.64 | MIT OR Apache-2.0 | https://github.com/strawlab/iana-time-zone |
|
||||||
|
| iana-time-zone-haiku | 0.1.2 | MIT OR Apache-2.0 | https://github.com/strawlab/iana-time-zone |
|
||||||
|
| icu_collections | 2.1.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_locale_core | 2.1.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_normalizer | 2.1.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_normalizer_data | 2.1.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_properties | 2.1.2 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_properties_data | 2.1.2 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| icu_provider | 2.1.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| id-arena | 2.3.0 | MIT/Apache-2.0 | https://github.com/fitzgen/id-arena |
|
||||||
|
| ident_case | 1.0.1 | MIT/Apache-2.0 | https://github.com/TedDriggs/ident_case |
|
||||||
|
| identity-hash | 0.1.0 | Apache-2.0 OR MIT | https://github.com/offsetting/identity-hash |
|
||||||
|
| idna | 1.1.0 | MIT OR Apache-2.0 | https://github.com/servo/rust-url/ |
|
||||||
|
| idna_adapter | 1.2.1 | Apache-2.0 OR MIT | https://github.com/hsivonen/idna_adapter |
|
||||||
|
| if-addrs | 0.15.0 | MIT OR BSD-3-Clause | https://github.com/messense/if-addrs |
|
||||||
|
| igd-next | 0.17.1 | MIT | https://github.com/dariusc93/rust-igd |
|
||||||
|
| image | 0.25.9 | MIT OR Apache-2.0 | https://github.com/image-rs/image |
|
||||||
|
| indexmap | 2.13.0 | Apache-2.0 OR MIT | https://github.com/indexmap-rs/indexmap |
|
||||||
|
| inout | 0.1.4 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| inplace-vec-builder | 0.1.1 | MIT OR Apache-2.0 | https://github.com/rklaehn/inplace-vec-builder |
|
||||||
|
| instant | 0.1.13 | BSD-3-Clause | https://github.com/sebcrozet/instant |
|
||||||
|
| ipconfig | 0.3.4 | MIT/Apache-2.0 | https://github.com/liranringel/ipconfig |
|
||||||
|
| ipnet | 2.12.0 | MIT OR Apache-2.0 | https://github.com/krisprice/ipnet |
|
||||||
|
| iri-string | 0.7.12 | MIT OR Apache-2.0 | https://github.com/lo48576/iri-string |
|
||||||
|
| iroh | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh |
|
||||||
|
| iroh-base | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh |
|
||||||
|
| iroh-blobs | 0.103.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh-blobs |
|
||||||
|
| iroh-dns | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh |
|
||||||
|
| iroh-io | 0.6.2 | Apache-2.0 OR MIT | https://github.com/n0-computer/iroh |
|
||||||
|
| iroh-metrics | 1.0.1 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh-metrics |
|
||||||
|
| iroh-metrics-derive | 1.0.1 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh-metrics |
|
||||||
|
| iroh-relay | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh |
|
||||||
|
| iroh-tickets | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh-tickets |
|
||||||
|
| iroh-util | 0.6.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh-util |
|
||||||
|
| irpc | 0.17.0 | Apache-2.0/MIT | https://github.com/n0-computer/irpc |
|
||||||
|
| irpc-derive | 0.17.0 | Apache-2.0/MIT | https://github.com/n0-computer/irpc |
|
||||||
|
| is-terminal | 0.4.17 | MIT | https://github.com/sunfishcode/is-terminal |
|
||||||
|
| itoa | 1.0.17 | MIT OR Apache-2.0 | https://github.com/dtolnay/itoa |
|
||||||
|
| jni | 0.21.1 | MIT/Apache-2.0 | https://github.com/jni-rs/jni-rs |
|
||||||
|
| jni | 0.22.4 | MIT OR Apache-2.0 | https://github.com/jni-rs/jni-rs |
|
||||||
|
| jni-macros | 0.22.4 | MIT OR Apache-2.0 | https://github.com/jni-rs/jni-rs |
|
||||||
|
| jni-sys | 0.3.1 | MIT OR Apache-2.0 | https://github.com/jni-rs/jni-sys |
|
||||||
|
| jni-sys | 0.4.1 | MIT OR Apache-2.0 | https://github.com/jni-rs/jni-sys |
|
||||||
|
| jni-sys-macros | 0.4.1 | MIT OR Apache-2.0 | https://github.com/jni-rs/jni-sys |
|
||||||
|
| js-sys | 0.3.85 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys |
|
||||||
|
| lazy_static | 1.5.0 | MIT OR Apache-2.0 | https://github.com/rust-lang-nursery/lazy-static.rs |
|
||||||
|
| leb128fmt | 0.1.0 | MIT OR Apache-2.0 | https://github.com/bluk/leb128fmt |
|
||||||
|
| libc | 0.2.180 | MIT OR Apache-2.0 | https://github.com/rust-lang/libc |
|
||||||
|
| libm | 0.2.16 | MIT | https://github.com/rust-lang/compiler-builtins |
|
||||||
|
| libredox | 0.1.14 | MIT | https://gitlab.redox-os.org/redox-os/libredox.git |
|
||||||
|
| libssh2-sys | 0.3.1 | MIT OR Apache-2.0 | https://github.com/alexcrichton/ssh2-rs |
|
||||||
|
| libz-sys | 1.1.29 | MIT OR Apache-2.0 | https://github.com/rust-lang/libz-sys |
|
||||||
|
| linux-raw-sys | 0.11.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/sunfishcode/linux-raw-sys |
|
||||||
|
| litemap | 0.8.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| lock_api | 0.4.14 | MIT OR Apache-2.0 | https://github.com/Amanieu/parking_lot |
|
||||||
|
| log | 0.4.29 | MIT OR Apache-2.0 | https://github.com/rust-lang/log |
|
||||||
|
| loom | 0.7.2 | MIT | https://github.com/tokio-rs/loom |
|
||||||
|
| lru | 0.12.5 | MIT | https://github.com/jeromefroe/lru-rs.git |
|
||||||
|
| lru | 0.16.3 | MIT | https://github.com/jeromefroe/lru-rs.git |
|
||||||
|
| lru | 0.18.0 | MIT | https://github.com/jeromefroe/lru-rs.git |
|
||||||
|
| lru | 0.7.8 | MIT | https://github.com/jeromefroe/lru-rs.git |
|
||||||
|
| lru-slab | 0.1.2 | MIT OR Apache-2.0 OR Zlib | https://github.com/Ralith/lru-slab |
|
||||||
|
| mac-addr | 0.3.0 | MIT | https://github.com/shellrow/mac-addr |
|
||||||
|
| mainline | 2.0.1 | MIT | https://github.com/nuhvi/mainline |
|
||||||
|
| matchers | 0.2.0 | MIT | https://github.com/hawkw/matchers |
|
||||||
|
| mdns-sd | 0.18.2 | Apache-2.0 OR MIT | https://github.com/keepsimple1/mdns-sd |
|
||||||
|
| memchr | 2.7.6 | Unlicense OR MIT | https://github.com/BurntSushi/memchr |
|
||||||
|
| mime | 0.3.17 | MIT OR Apache-2.0 | https://github.com/hyperium/mime |
|
||||||
|
| minimal-lexical | 0.2.1 | MIT/Apache-2.0 | https://github.com/Alexhuszagh/minimal-lexical |
|
||||||
|
| miniz_oxide | 0.8.9 | MIT OR Zlib OR Apache-2.0 | https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide |
|
||||||
|
| mio | 1.1.1 | MIT | https://github.com/tokio-rs/mio |
|
||||||
|
| moka | 0.12.15 | (MIT OR Apache-2.0) AND Apache-2.0 | https://github.com/moka-rs/moka |
|
||||||
|
| moxcms | 0.7.11 | BSD-3-Clause OR Apache-2.0 | https://github.com/awxkee/moxcms.git |
|
||||||
|
| n0-error | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/n0-error |
|
||||||
|
| n0-error-macros | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/n0-error |
|
||||||
|
| n0-future | 0.3.2 | MIT OR Apache-2.0 | https://github.com/n0-computer/n0-future |
|
||||||
|
| n0-watcher | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/n0-watcher |
|
||||||
|
| ndk-context | 0.1.1 | MIT OR Apache-2.0 | https://github.com/rust-windowing/android-ndk-rs |
|
||||||
|
| negentropy | 0.5.0 | MIT | https://github.com/rust-nostr/negentropy.git |
|
||||||
|
| nested_enum_utils | 0.2.3 | MIT OR Apache-2.0 | https://github.com/n0-computer/nested-enum-utils |
|
||||||
|
| netdev | 0.44.0 | MIT | https://github.com/shellrow/netdev |
|
||||||
|
| netlink-packet-core | 0.8.1 | MIT | https://github.com/rust-netlink/netlink-packet-core |
|
||||||
|
| netlink-packet-route | 0.29.0 | MIT | https://github.com/rust-netlink/netlink-packet-route |
|
||||||
|
| netlink-packet-route | 0.31.0 | MIT | https://github.com/rust-netlink/netlink-packet-route |
|
||||||
|
| netlink-proto | 0.12.0 | MIT | https://github.com/rust-netlink/netlink-proto |
|
||||||
|
| netlink-sys | 0.8.8 | MIT | https://github.com/rust-netlink/netlink-sys |
|
||||||
|
| netwatch | 0.19.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/net-tools |
|
||||||
|
| nom | 7.1.3 | MIT | https://github.com/Geal/nom |
|
||||||
|
| noq | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/noq |
|
||||||
|
| noq-proto | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/noq |
|
||||||
|
| noq-udp | 1.0.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/noq |
|
||||||
|
| nostr | 0.44.2 | MIT | https://github.com/rust-nostr/nostr.git |
|
||||||
|
| nostr-database | 0.44.0 | MIT | https://github.com/rust-nostr/nostr.git |
|
||||||
|
| nostr-gossip | 0.44.0 | MIT | https://github.com/rust-nostr/nostr.git |
|
||||||
|
| nostr-relay-pool | 0.44.0 | MIT | https://github.com/rust-nostr/nostr.git |
|
||||||
|
| nostr-sdk | 0.44.1 | MIT | https://github.com/rust-nostr/nostr.git |
|
||||||
|
| nu-ansi-term | 0.50.3 | MIT | https://github.com/nushell/nu-ansi-term |
|
||||||
|
| num-bigint | 0.4.6 | MIT OR Apache-2.0 | https://github.com/rust-num/num-bigint |
|
||||||
|
| num-conv | 0.2.2 | MIT OR Apache-2.0 | https://github.com/jhpratt/num-conv |
|
||||||
|
| num-integer | 0.1.46 | MIT OR Apache-2.0 | https://github.com/rust-num/num-integer |
|
||||||
|
| num-traits | 0.2.19 | MIT OR Apache-2.0 | https://github.com/rust-num/num-traits |
|
||||||
|
| num_enum | 0.7.6 | BSD-3-Clause OR MIT OR Apache-2.0 | https://github.com/illicitonion/num_enum |
|
||||||
|
| num_enum_derive | 0.7.6 | BSD-3-Clause OR MIT OR Apache-2.0 | https://github.com/illicitonion/num_enum |
|
||||||
|
| num_threads | 0.1.7 | MIT OR Apache-2.0 | https://github.com/jhpratt/num_threads |
|
||||||
|
| objc2 | 0.6.4 | MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-core-foundation | 0.3.2 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-core-wlan | 0.3.2 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-encode | 4.1.0 | MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-foundation | 0.3.2 | MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-security | 0.3.2 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-security-foundation | 0.3.2 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| objc2-system-configuration | 0.3.2 | Zlib OR Apache-2.0 OR MIT | https://github.com/madsmtm/objc2 |
|
||||||
|
| oid-registry | 0.8.1 | MIT OR Apache-2.0 | https://github.com/rusticata/oid-registry.git |
|
||||||
|
| once_cell | 1.21.3 | MIT OR Apache-2.0 | https://github.com/matklad/once_cell |
|
||||||
|
| opaque-debug | 0.3.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/utils |
|
||||||
|
| openssl-probe | 0.2.1 | MIT OR Apache-2.0 | https://github.com/rustls/openssl-probe |
|
||||||
|
| openssl-sys | 0.9.117 | MIT | https://github.com/rust-openssl/rust-openssl |
|
||||||
|
| papaya | 0.2.4 | MIT | https://github.com/ibraheemdev/papaya |
|
||||||
|
| parking | 2.2.1 | Apache-2.0 OR MIT | https://github.com/smol-rs/parking |
|
||||||
|
| parking_lot | 0.11.2 | Apache-2.0/MIT | https://github.com/Amanieu/parking_lot |
|
||||||
|
| parking_lot | 0.12.5 | MIT OR Apache-2.0 | https://github.com/Amanieu/parking_lot |
|
||||||
|
| parking_lot_core | 0.8.6 | Apache-2.0/MIT | https://github.com/Amanieu/parking_lot |
|
||||||
|
| parking_lot_core | 0.9.12 | MIT OR Apache-2.0 | https://github.com/Amanieu/parking_lot |
|
||||||
|
| password-hash | 0.5.0 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits/tree/master/password-hash |
|
||||||
|
| paste | 1.0.15 | MIT OR Apache-2.0 | https://github.com/dtolnay/paste |
|
||||||
|
| pbkdf2 | 0.12.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/password-hashes/tree/master/pbkdf2 |
|
||||||
|
| pem | 3.0.6 | MIT | https://github.com/jcreekmore/pem-rs.git |
|
||||||
|
| pem-rfc7468 | 1.0.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| percent-encoding | 2.3.2 | MIT OR Apache-2.0 | https://github.com/servo/rust-url/ |
|
||||||
|
| pharos | 0.5.3 | Unlicense | https://github.com/najamelan/pharos |
|
||||||
|
| pin-project | 1.1.13 | Apache-2.0 OR MIT | https://github.com/taiki-e/pin-project |
|
||||||
|
| pin-project-internal | 1.1.13 | Apache-2.0 OR MIT | https://github.com/taiki-e/pin-project |
|
||||||
|
| pin-project-lite | 0.2.16 | Apache-2.0 OR MIT | https://github.com/taiki-e/pin-project-lite |
|
||||||
|
| pin-utils | 0.1.0 | MIT OR Apache-2.0 | https://github.com/rust-lang-nursery/pin-utils |
|
||||||
|
| pkcs8 | 0.10.2 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats/tree/master/pkcs8 |
|
||||||
|
| pkcs8 | 0.11.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| pkg-config | 0.3.33 | MIT OR Apache-2.0 | https://github.com/rust-lang/pkg-config-rs |
|
||||||
|
| plain | 0.2.3 | MIT/Apache-2.0 | https://github.com/randomites/plain |
|
||||||
|
| plist | 1.9.0 | MIT | https://github.com/ebarnard/rust-plist/ |
|
||||||
|
| poly1305 | 0.8.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/universal-hashes |
|
||||||
|
| polyval | 0.6.2 | Apache-2.0 OR MIT | https://github.com/RustCrypto/universal-hashes |
|
||||||
|
| portable-atomic | 1.13.1 | Apache-2.0 OR MIT | https://github.com/taiki-e/portable-atomic |
|
||||||
|
| portmapper | 0.19.0 | MIT OR Apache-2.0 | https://github.com/n0-computer/net-tools |
|
||||||
|
| positioned-io | 0.3.5 | MIT | https://github.com/vasi/positioned-io |
|
||||||
|
| postcard | 1.1.3 | MIT OR Apache-2.0 | https://github.com/jamesmunns/postcard |
|
||||||
|
| postcard-derive | 0.2.2 | MIT OR Apache-2.0 | https://github.com/jamesmunns/postcard |
|
||||||
|
| potential_utf | 0.1.4 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| powerfmt | 0.2.0 | MIT OR Apache-2.0 | https://github.com/jhpratt/powerfmt |
|
||||||
|
| ppv-lite86 | 0.2.21 | MIT OR Apache-2.0 | https://github.com/cryptocorrosion/cryptocorrosion |
|
||||||
|
| prefix-trie | 0.8.4 | MIT OR Apache-2.0 | https://github.com/tiborschneider/prefix-trie |
|
||||||
|
| prettyplease | 0.2.37 | MIT OR Apache-2.0 | https://github.com/dtolnay/prettyplease |
|
||||||
|
| proc-macro-crate | 3.5.0 | MIT OR Apache-2.0 | https://github.com/bkchr/proc-macro-crate |
|
||||||
|
| proc-macro-error | 0.4.12 | MIT OR Apache-2.0 | https://gitlab.com/CreepySkeleton/proc-macro-error |
|
||||||
|
| proc-macro-error-attr | 0.4.12 | MIT OR Apache-2.0 | https://gitlab.com/CreepySkeleton/proc-macro-error |
|
||||||
|
| proc-macro-hack | 0.5.20+deprecated | MIT OR Apache-2.0 | https://github.com/dtolnay/proc-macro-hack |
|
||||||
|
| proc-macro2 | 1.0.106 | MIT OR Apache-2.0 | https://github.com/dtolnay/proc-macro2 |
|
||||||
|
| pxfm | 0.1.28 | BSD-3-Clause OR Apache-2.0 | https://github.com/awxkee/pxfm |
|
||||||
|
| qrcode | 0.14.1 | MIT OR Apache-2.0 | https://github.com/kennytm/qrcode-rust |
|
||||||
|
| quick-xml | 0.39.4 | MIT | https://github.com/tafia/quick-xml |
|
||||||
|
| quote | 1.0.44 | MIT OR Apache-2.0 | https://github.com/dtolnay/quote |
|
||||||
|
| r-efi | 5.3.0 | MIT OR Apache-2.0 OR LGPL-2.1-or-later | https://github.com/r-efi/r-efi |
|
||||||
|
| r-efi | 6.0.0 | MIT OR Apache-2.0 OR LGPL-2.1-or-later | https://github.com/r-efi/r-efi |
|
||||||
|
| rand | 0.10.1 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand | 0.8.5 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand | 0.9.2 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand_chacha | 0.3.1 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand_chacha | 0.9.0 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand_core | 0.10.1 | MIT OR Apache-2.0 | https://github.com/rust-random/rand_core |
|
||||||
|
| rand_core | 0.6.4 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand_core | 0.9.5 | MIT OR Apache-2.0 | https://github.com/rust-random/rand |
|
||||||
|
| rand_pcg | 0.10.2 | MIT OR Apache-2.0 | https://github.com/rust-random/rngs |
|
||||||
|
| range-collections | 0.4.6 | MIT OR Apache-2.0 | https://github.com/rklaehn/range-collections |
|
||||||
|
| rcgen | 0.14.8 | MIT OR Apache-2.0 | https://github.com/rustls/rcgen |
|
||||||
|
| redb | 4.1.0 | MIT OR Apache-2.0 | https://github.com/cberner/redb |
|
||||||
|
| redox_syscall | 0.2.16 | MIT | https://gitlab.redox-os.org/redox-os/syscall |
|
||||||
|
| redox_syscall | 0.5.18 | MIT | https://gitlab.redox-os.org/redox-os/syscall |
|
||||||
|
| redox_syscall | 0.7.3 | MIT | https://gitlab.redox-os.org/redox-os/syscall |
|
||||||
|
| reed-solomon-erasure | 6.0.0 | MIT | https://github.com/darrenldl/reed-solomon-erasure |
|
||||||
|
| ref-cast | 1.0.25 | MIT OR Apache-2.0 | https://github.com/dtolnay/ref-cast |
|
||||||
|
| ref-cast-impl | 1.0.25 | MIT OR Apache-2.0 | https://github.com/dtolnay/ref-cast |
|
||||||
|
| reflink-copy | 0.1.29 | MIT/Apache-2.0 | https://github.com/cargo-bins/reflink-copy |
|
||||||
|
| regex | 1.12.2 | MIT OR Apache-2.0 | https://github.com/rust-lang/regex |
|
||||||
|
| regex-automata | 0.4.13 | MIT OR Apache-2.0 | https://github.com/rust-lang/regex |
|
||||||
|
| regex-syntax | 0.8.8 | MIT OR Apache-2.0 | https://github.com/rust-lang/regex |
|
||||||
|
| reqwest | 0.11.27 | MIT OR Apache-2.0 | https://github.com/seanmonstar/reqwest |
|
||||||
|
| reqwest | 0.13.4 | MIT OR Apache-2.0 | https://github.com/seanmonstar/reqwest |
|
||||||
|
| resolv-conf | 0.7.6 | MIT OR Apache-2.0 | https://github.com/hickory-dns/resolv-conf |
|
||||||
|
| ring | 0.17.14 | Apache-2.0 AND ISC | https://github.com/briansmith/ring |
|
||||||
|
| rustc-hash | 2.1.2 | Apache-2.0 OR MIT | https://github.com/rust-lang/rustc-hash |
|
||||||
|
| rustc_version | 0.4.1 | MIT OR Apache-2.0 | https://github.com/djc/rustc-version-rs |
|
||||||
|
| rusticata-macros | 4.1.0 | MIT/Apache-2.0 | https://github.com/rusticata/rusticata-macros.git |
|
||||||
|
| rustix | 1.1.3 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/rustix |
|
||||||
|
| rustls | 0.21.12 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/rustls |
|
||||||
|
| rustls | 0.23.36 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/rustls |
|
||||||
|
| rustls-native-certs | 0.8.4 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/rustls-native-certs |
|
||||||
|
| rustls-pemfile | 1.0.4 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/pemfile |
|
||||||
|
| rustls-pki-types | 1.14.0 | MIT OR Apache-2.0 | https://github.com/rustls/pki-types |
|
||||||
|
| rustls-platform-verifier | 0.7.0 | MIT OR Apache-2.0 | https://github.com/rustls/rustls-platform-verifier |
|
||||||
|
| rustls-platform-verifier-android | 0.1.1 | MIT OR Apache-2.0 | https://github.com/rustls/rustls-platform-verifier |
|
||||||
|
| rustls-webpki | 0.101.7 | ISC | https://github.com/rustls/webpki |
|
||||||
|
| rustls-webpki | 0.103.9 | ISC | https://github.com/rustls/webpki |
|
||||||
|
| rustversion | 1.0.22 | MIT OR Apache-2.0 | https://github.com/dtolnay/rustversion |
|
||||||
|
| ryu | 1.0.22 | Apache-2.0 OR BSL-1.0 | https://github.com/dtolnay/ryu |
|
||||||
|
| salsa20 | 0.10.2 | MIT OR Apache-2.0 | https://github.com/RustCrypto/stream-ciphers |
|
||||||
|
| same-file | 1.0.6 | Unlicense/MIT | https://github.com/BurntSushi/same-file |
|
||||||
|
| schannel | 0.1.29 | MIT | https://github.com/steffengy/schannel-rs |
|
||||||
|
| scoped-tls | 1.0.1 | MIT/Apache-2.0 | https://github.com/alexcrichton/scoped-tls |
|
||||||
|
| scopeguard | 1.2.0 | MIT OR Apache-2.0 | https://github.com/bluss/scopeguard |
|
||||||
|
| scrypt | 0.11.0 | MIT OR Apache-2.0 | https://github.com/RustCrypto/password-hashes/tree/master/scrypt |
|
||||||
|
| sct | 0.7.1 | Apache-2.0 OR ISC OR MIT | https://github.com/rustls/sct.rs |
|
||||||
|
| sd-notify | 0.4.5 | MIT OR Apache-2.0 | https://github.com/lnicola/sd-notify |
|
||||||
|
| secp256k1 | 0.29.1 | CC0-1.0 | https://github.com/rust-bitcoin/rust-secp256k1/ |
|
||||||
|
| secp256k1-sys | 0.10.1 | CC0-1.0 | https://github.com/rust-bitcoin/rust-secp256k1/ |
|
||||||
|
| security-framework | 3.7.0 | MIT OR Apache-2.0 | https://github.com/kornelski/rust-security-framework |
|
||||||
|
| security-framework-sys | 2.17.0 | MIT OR Apache-2.0 | https://github.com/kornelski/rust-security-framework |
|
||||||
|
| seize | 0.5.1 | MIT | https://github.com/ibraheemdev/seize |
|
||||||
|
| self_cell | 1.2.2 | Apache-2.0 OR GPL-2.0-only | https://github.com/Voultapher/self_cell |
|
||||||
|
| semver | 1.0.27 | MIT OR Apache-2.0 | https://github.com/dtolnay/semver |
|
||||||
|
| send_wrapper | 0.6.0 | MIT/Apache-2.0 | https://github.com/thk1/send_wrapper |
|
||||||
|
| serde | 1.0.228 | MIT OR Apache-2.0 | https://github.com/serde-rs/serde |
|
||||||
|
| serde_bencode | 0.2.4 | MIT | https://github.com/toby/serde-bencode |
|
||||||
|
| serde_bytes | 0.11.19 | MIT OR Apache-2.0 | https://github.com/serde-rs/bytes |
|
||||||
|
| serde_core | 1.0.228 | MIT OR Apache-2.0 | https://github.com/serde-rs/serde |
|
||||||
|
| serde_derive | 1.0.228 | MIT OR Apache-2.0 | https://github.com/serde-rs/serde |
|
||||||
|
| serde_json | 1.0.149 | MIT OR Apache-2.0 | https://github.com/serde-rs/json |
|
||||||
|
| serde_spanned | 0.6.9 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| serde_urlencoded | 0.7.1 | MIT/Apache-2.0 | https://github.com/nox/serde_urlencoded |
|
||||||
|
| serde_yaml | 0.9.34+deprecated | MIT OR Apache-2.0 | https://github.com/dtolnay/serde-yaml |
|
||||||
|
| serdect | 0.4.3 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| serial2 | 0.2.34 | BSD-2-Clause OR Apache-2.0 | https://github.com/de-vri-es/serial2-rs |
|
||||||
|
| serial2-tokio | 0.1.21 | BSD-2-Clause OR Apache-2.0 | https://github.com/de-vri-es/serial2-tokio-rs |
|
||||||
|
| sha-1 | 0.10.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hashes |
|
||||||
|
| sha1 | 0.10.6 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hashes |
|
||||||
|
| sha1_smol | 1.0.1 | BSD-3-Clause | https://github.com/mitsuhiko/sha1-smol |
|
||||||
|
| sha2 | 0.10.9 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hashes |
|
||||||
|
| sha2 | 0.11.0 | MIT OR Apache-2.0 | https://github.com/RustCrypto/hashes |
|
||||||
|
| sharded-slab | 0.1.7 | MIT | https://github.com/hawkw/sharded-slab |
|
||||||
|
| shlex | 1.3.0 | MIT OR Apache-2.0 | https://github.com/comex/rust-shlex |
|
||||||
|
| signal-hook-registry | 1.4.8 | MIT OR Apache-2.0 | https://github.com/vorner/signal-hook |
|
||||||
|
| signature | 2.2.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/traits/tree/master/signature |
|
||||||
|
| signature | 3.0.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/traits |
|
||||||
|
| simd-adler32 | 0.3.8 | MIT | https://github.com/mcountryman/simd-adler32 |
|
||||||
|
| simd_cesu8 | 1.1.1 | Apache-2.0 OR MIT | https://github.com/seancroach/simd_cesu8 |
|
||||||
|
| simdutf8 | 0.1.5 | MIT OR Apache-2.0 | https://github.com/rusticstuff/simdutf8 |
|
||||||
|
| simple-dns | 0.11.3 | MIT | https://github.com/balliegojr/simple-dns |
|
||||||
|
| siphasher | 1.0.3 | MIT/Apache-2.0 | https://github.com/jedisct1/rust-siphash |
|
||||||
|
| slab | 0.4.11 | MIT | https://github.com/tokio-rs/slab |
|
||||||
|
| smallvec | 1.15.1 | MIT OR Apache-2.0 | https://github.com/servo/rust-smallvec |
|
||||||
|
| socket-pktinfo | 0.3.2 | MIT | https://github.com/pixsper/socket-pktinfo |
|
||||||
|
| socket2 | 0.5.10 | MIT OR Apache-2.0 | https://github.com/rust-lang/socket2 |
|
||||||
|
| socket2 | 0.6.2 | MIT OR Apache-2.0 | https://github.com/rust-lang/socket2 |
|
||||||
|
| sorted-index-buffer | 0.2.1 | MIT OR Apache-2.0 | https://github.com/n0-computer/iroh |
|
||||||
|
| spez | 0.1.2 | BSD-2-Clause | https://github.com/m-ou-se/spez |
|
||||||
|
| spin | 0.10.0 | MIT | https://github.com/mvdnes/spin-rs.git |
|
||||||
|
| spin | 0.9.8 | MIT | https://github.com/mvdnes/spin-rs.git |
|
||||||
|
| spki | 0.7.3 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats/tree/master/spki |
|
||||||
|
| spki | 0.8.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/formats |
|
||||||
|
| ssh2 | 0.9.5 | MIT OR Apache-2.0 | https://github.com/alexcrichton/ssh2-rs |
|
||||||
|
| stable_deref_trait | 1.2.1 | MIT OR Apache-2.0 | https://github.com/storyyeller/stable_deref_trait |
|
||||||
|
| strsim | 0.11.1 | MIT | https://github.com/rapidfuzz/strsim-rs |
|
||||||
|
| strum | 0.28.0 | MIT | https://github.com/Peternator7/strum |
|
||||||
|
| strum_macros | 0.28.0 | MIT | https://github.com/Peternator7/strum |
|
||||||
|
| subtle | 2.6.1 | BSD-3-Clause | https://github.com/dalek-cryptography/subtle |
|
||||||
|
| syn | 1.0.109 | MIT OR Apache-2.0 | https://github.com/dtolnay/syn |
|
||||||
|
| syn | 2.0.114 | MIT OR Apache-2.0 | https://github.com/dtolnay/syn |
|
||||||
|
| syn-mid | 0.5.4 | Apache-2.0 OR MIT | https://github.com/taiki-e/syn-mid |
|
||||||
|
| sync_wrapper | 0.1.2 | Apache-2.0 | https://github.com/Actyx/sync_wrapper |
|
||||||
|
| sync_wrapper | 1.0.2 | Apache-2.0 | https://github.com/Actyx/sync_wrapper |
|
||||||
|
| synstructure | 0.13.2 | MIT | https://github.com/mystor/synstructure |
|
||||||
|
| system-configuration | 0.5.1 | MIT OR Apache-2.0 | https://github.com/mullvad/system-configuration-rs |
|
||||||
|
| system-configuration | 0.6.1 | MIT OR Apache-2.0 | https://github.com/mullvad/system-configuration-rs |
|
||||||
|
| system-configuration | 0.7.0 | MIT OR Apache-2.0 | https://github.com/mullvad/system-configuration-rs |
|
||||||
|
| system-configuration-sys | 0.5.0 | MIT OR Apache-2.0 | https://github.com/mullvad/system-configuration-rs |
|
||||||
|
| system-configuration-sys | 0.6.0 | MIT OR Apache-2.0 | https://github.com/mullvad/system-configuration-rs |
|
||||||
|
| tagptr | 0.2.0 | MIT/Apache-2.0 | https://github.com/oliver-giersch/tagptr.git |
|
||||||
|
| tar | 0.4.44 | MIT OR Apache-2.0 | https://github.com/alexcrichton/tar-rs |
|
||||||
|
| tempfile | 3.24.0 | MIT OR Apache-2.0 | https://github.com/Stebalien/tempfile |
|
||||||
|
| termcolor | 1.4.1 | Unlicense OR MIT | https://github.com/BurntSushi/termcolor |
|
||||||
|
| thiserror | 1.0.69 | MIT OR Apache-2.0 | https://github.com/dtolnay/thiserror |
|
||||||
|
| thiserror | 2.0.18 | MIT OR Apache-2.0 | https://github.com/dtolnay/thiserror |
|
||||||
|
| thiserror-impl | 1.0.69 | MIT OR Apache-2.0 | https://github.com/dtolnay/thiserror |
|
||||||
|
| thiserror-impl | 2.0.18 | MIT OR Apache-2.0 | https://github.com/dtolnay/thiserror |
|
||||||
|
| thread_local | 1.1.9 | MIT OR Apache-2.0 | https://github.com/Amanieu/thread_local-rs |
|
||||||
|
| time | 0.3.49 | MIT OR Apache-2.0 | https://github.com/time-rs/time |
|
||||||
|
| time-core | 0.1.9 | MIT OR Apache-2.0 | https://github.com/time-rs/time |
|
||||||
|
| time-macros | 0.2.29 | MIT OR Apache-2.0 | https://github.com/time-rs/time |
|
||||||
|
| tinystr | 0.8.2 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| tinyvec | 1.10.0 | Zlib OR Apache-2.0 OR MIT | https://github.com/Lokathor/tinyvec |
|
||||||
|
| tinyvec_macros | 0.1.1 | MIT OR Apache-2.0 OR Zlib | https://github.com/Soveu/tinyvec_macros |
|
||||||
|
| tokio | 1.49.0 | MIT | https://github.com/tokio-rs/tokio |
|
||||||
|
| tokio-macros | 2.6.0 | MIT | https://github.com/tokio-rs/tokio |
|
||||||
|
| tokio-rustls | 0.24.1 | MIT/Apache-2.0 | https://github.com/rustls/tokio-rustls |
|
||||||
|
| tokio-rustls | 0.26.4 | MIT OR Apache-2.0 | https://github.com/rustls/tokio-rustls |
|
||||||
|
| tokio-socks | 0.5.2 | MIT | https://github.com/sticnarf/tokio-socks |
|
||||||
|
| tokio-stream | 0.1.18 | MIT | https://github.com/tokio-rs/tokio |
|
||||||
|
| tokio-test | 0.4.5 | MIT | https://github.com/tokio-rs/tokio |
|
||||||
|
| tokio-tungstenite | 0.20.1 | MIT | https://github.com/snapview/tokio-tungstenite |
|
||||||
|
| tokio-tungstenite | 0.26.2 | MIT | https://github.com/snapview/tokio-tungstenite |
|
||||||
|
| tokio-util | 0.7.18 | MIT | https://github.com/tokio-rs/tokio |
|
||||||
|
| tokio-websockets | 0.13.2 | MIT | https://github.com/Gelbpunkt/tokio-websockets/ |
|
||||||
|
| toml | 0.8.23 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_datetime | 0.6.11 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_datetime | 1.1.1+spec-1.1.0 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_edit | 0.22.27 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_edit | 0.25.12+spec-1.1.0 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_parser | 1.1.2+spec-1.1.0 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| toml_write | 0.1.2 | MIT OR Apache-2.0 | https://github.com/toml-rs/toml |
|
||||||
|
| totp-rs | 5.7.0 | MIT | https://github.com/constantoine/totp-rs |
|
||||||
|
| tower | 0.5.3 | MIT | https://github.com/tower-rs/tower |
|
||||||
|
| tower-http | 0.6.8 | MIT | https://github.com/tower-rs/tower-http |
|
||||||
|
| tower-layer | 0.3.3 | MIT | https://github.com/tower-rs/tower |
|
||||||
|
| tower-service | 0.3.3 | MIT | https://github.com/tower-rs/tower |
|
||||||
|
| tracing | 0.1.44 | MIT | https://github.com/tokio-rs/tracing |
|
||||||
|
| tracing-attributes | 0.1.31 | MIT | https://github.com/tokio-rs/tracing |
|
||||||
|
| tracing-core | 0.1.36 | MIT | https://github.com/tokio-rs/tracing |
|
||||||
|
| tracing-log | 0.2.0 | MIT | https://github.com/tokio-rs/tracing |
|
||||||
|
| tracing-subscriber | 0.3.22 | MIT | https://github.com/tokio-rs/tracing |
|
||||||
|
| try-lock | 0.2.5 | MIT | https://github.com/seanmonstar/try-lock |
|
||||||
|
| tungstenite | 0.20.1 | MIT OR Apache-2.0 | https://github.com/snapview/tungstenite-rs |
|
||||||
|
| tungstenite | 0.26.2 | MIT OR Apache-2.0 | https://github.com/snapview/tungstenite-rs |
|
||||||
|
| typenum | 1.20.1 | MIT OR Apache-2.0 | https://github.com/paholg/typenum |
|
||||||
|
| unicode-ident | 1.0.22 | (MIT OR Apache-2.0) AND Unicode-3.0 | https://github.com/dtolnay/unicode-ident |
|
||||||
|
| unicode-normalization | 0.1.22 | MIT/Apache-2.0 | https://github.com/unicode-rs/unicode-normalization |
|
||||||
|
| unicode-segmentation | 1.13.3 | MIT OR Apache-2.0 | https://github.com/unicode-rs/unicode-segmentation |
|
||||||
|
| unicode-xid | 0.2.6 | MIT OR Apache-2.0 | https://github.com/unicode-rs/unicode-xid |
|
||||||
|
| universal-hash | 0.5.1 | MIT OR Apache-2.0 | https://github.com/RustCrypto/traits |
|
||||||
|
| unsafe-libyaml | 0.2.11 | MIT | https://github.com/dtolnay/unsafe-libyaml |
|
||||||
|
| untrusted | 0.9.0 | ISC | https://github.com/briansmith/untrusted |
|
||||||
|
| url | 2.5.8 | MIT OR Apache-2.0 | https://github.com/servo/rust-url |
|
||||||
|
| urlencoding | 2.1.3 | MIT | https://github.com/kornelski/rust_urlencoding |
|
||||||
|
| utf-8 | 0.7.6 | MIT OR Apache-2.0 | https://github.com/SimonSapin/rust-utf8 |
|
||||||
|
| utf8_iter | 1.0.4 | Apache-2.0 OR MIT | https://github.com/hsivonen/utf8_iter |
|
||||||
|
| uuid | 1.19.0 | Apache-2.0 OR MIT | https://github.com/uuid-rs/uuid |
|
||||||
|
| valuable | 0.1.1 | MIT | https://github.com/tokio-rs/valuable |
|
||||||
|
| vcpkg | 0.2.15 | MIT/Apache-2.0 | https://github.com/mcgoo/vcpkg-rs |
|
||||||
|
| vergen | 9.1.0 | MIT OR Apache-2.0 | https://github.com/rustyhorde/vergen |
|
||||||
|
| vergen-gitcl | 9.1.0 | MIT OR Apache-2.0 | https://github.com/rustyhorde/vergen |
|
||||||
|
| vergen-lib | 9.1.0 | MIT OR Apache-2.0 | https://github.com/rustyhorde/vergen |
|
||||||
|
| version_check | 0.9.5 | MIT/Apache-2.0 | https://github.com/SergioBenitez/version_check |
|
||||||
|
| walkdir | 2.5.0 | Unlicense/MIT | https://github.com/BurntSushi/walkdir |
|
||||||
|
| want | 0.3.1 | MIT | https://github.com/seanmonstar/want |
|
||||||
|
| wasi | 0.11.1+wasi-snapshot-preview1 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasi |
|
||||||
|
| wasip2 | 1.0.2+wasi-0.2.9 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasi-rs |
|
||||||
|
| wasip3 | 0.4.0+wasi-0.3.0-rc-2026-01-06 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasi-rs |
|
||||||
|
| wasm-bindgen | 0.2.108 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen |
|
||||||
|
| wasm-bindgen-futures | 0.4.58 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/futures |
|
||||||
|
| wasm-bindgen-macro | 0.2.108 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro |
|
||||||
|
| wasm-bindgen-macro-support | 0.2.108 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support |
|
||||||
|
| wasm-bindgen-shared | 0.2.108 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared |
|
||||||
|
| wasm-encoder | 0.244.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder |
|
||||||
|
| wasm-metadata | 0.244.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata |
|
||||||
|
| wasm-streams | 0.4.2 | MIT OR Apache-2.0 | https://github.com/MattiasBuelens/wasm-streams/ |
|
||||||
|
| wasm-streams | 0.5.0 | MIT OR Apache-2.0 | https://github.com/MattiasBuelens/wasm-streams/ |
|
||||||
|
| wasmparser | 0.244.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser |
|
||||||
|
| web-sys | 0.3.85 | MIT OR Apache-2.0 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/web-sys |
|
||||||
|
| web-time | 1.1.0 | MIT OR Apache-2.0 | https://github.com/daxpedda/web-time |
|
||||||
|
| webpki-root-certs | 1.0.7 | CDLA-Permissive-2.0 | https://github.com/rustls/webpki-roots |
|
||||||
|
| webpki-roots | 0.25.4 | MPL-2.0 | https://github.com/rustls/webpki-roots |
|
||||||
|
| webpki-roots | 0.26.11 | CDLA-Permissive-2.0 | https://github.com/rustls/webpki-roots |
|
||||||
|
| webpki-roots | 1.0.6 | CDLA-Permissive-2.0 | https://github.com/rustls/webpki-roots |
|
||||||
|
| widestring | 1.2.1 | MIT OR Apache-2.0 | https://github.com/VoidStarKat/widestring-rs |
|
||||||
|
| winapi | 0.3.9 | MIT/Apache-2.0 | https://github.com/retep998/winapi-rs |
|
||||||
|
| winapi-i686-pc-windows-gnu | 0.4.0 | MIT/Apache-2.0 | https://github.com/retep998/winapi-rs |
|
||||||
|
| winapi-util | 0.1.11 | Unlicense OR MIT | https://github.com/BurntSushi/winapi-util |
|
||||||
|
| winapi-x86_64-pc-windows-gnu | 0.4.0 | MIT/Apache-2.0 | https://github.com/retep998/winapi-rs |
|
||||||
|
| windows | 0.62.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-collections | 0.3.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-core | 0.62.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-future | 0.3.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-implement | 0.60.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-interface | 0.59.3 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-link | 0.2.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-numerics | 0.3.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-registry | 0.6.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-result | 0.4.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-strings | 0.5.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-sys | 0.45.0 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-sys | 0.48.0 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-sys | 0.52.0 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-sys | 0.60.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-sys | 0.61.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-targets | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-targets | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-targets | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-targets | 0.53.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows-threading | 0.2.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_gnullvm | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_gnullvm | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_gnullvm | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_gnullvm | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_msvc | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_msvc | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_msvc | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_aarch64_msvc | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnu | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnu | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnu | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnu | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnullvm | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_gnullvm | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_msvc | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_msvc | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_msvc | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_i686_msvc | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnu | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnu | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnu | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnu | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnullvm | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnullvm | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnullvm | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_gnullvm | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_msvc | 0.42.2 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_msvc | 0.48.5 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_msvc | 0.52.6 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| windows_x86_64_msvc | 0.53.1 | MIT OR Apache-2.0 | https://github.com/microsoft/windows-rs |
|
||||||
|
| winnow | 0.7.14 | MIT | https://github.com/winnow-rs/winnow |
|
||||||
|
| winnow | 1.0.3 | MIT | https://github.com/winnow-rs/winnow |
|
||||||
|
| winreg | 0.50.0 | MIT | https://github.com/gentoo90/winreg-rs |
|
||||||
|
| wit-bindgen | 0.51.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wit-bindgen |
|
||||||
|
| wit-bindgen-core | 0.51.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wit-bindgen |
|
||||||
|
| wit-bindgen-rust | 0.51.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wit-bindgen |
|
||||||
|
| wit-bindgen-rust-macro | 0.51.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wit-bindgen |
|
||||||
|
| wit-component | 0.244.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component |
|
||||||
|
| wit-parser | 0.244.0 | Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT | https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser |
|
||||||
|
| wmi | 0.18.4 | MIT OR Apache-2.0 | https://github.com/ohadravid/wmi-rs |
|
||||||
|
| writeable | 0.6.2 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| ws_stream_wasm | 0.7.5 | Unlicense | https://github.com/najamelan/ws_stream_wasm |
|
||||||
|
| x509-parser | 0.18.1 | MIT OR Apache-2.0 | https://github.com/rusticata/x509-parser.git |
|
||||||
|
| xattr | 1.6.1 | MIT OR Apache-2.0 | https://github.com/Stebalien/xattr |
|
||||||
|
| xml-rs | 0.8.28 | MIT | https://github.com/kornelski/xml-rs |
|
||||||
|
| xmltree | 0.10.3 | MIT | https://github.com/eminence/xmltree-rs |
|
||||||
|
| yasna | 0.6.0 | MIT OR Apache-2.0 | https://github.com/qnighy/yasna.rs |
|
||||||
|
| yoke | 0.8.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| yoke-derive | 0.8.1 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zbase32 | 0.1.2 | LGPL-3.0+ | https://gitlab.com/pgerber/zbase32-rust |
|
||||||
|
| zerocopy | 0.8.33 | BSD-2-Clause OR Apache-2.0 OR MIT | https://github.com/google/zerocopy |
|
||||||
|
| zerocopy-derive | 0.8.33 | BSD-2-Clause OR Apache-2.0 OR MIT | https://github.com/google/zerocopy |
|
||||||
|
| zerofrom | 0.1.6 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zerofrom-derive | 0.1.6 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zeroize | 1.9.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/utils |
|
||||||
|
| zeroize_derive | 1.5.0 | Apache-2.0 OR MIT | https://github.com/RustCrypto/utils |
|
||||||
|
| zerotrie | 0.2.3 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zerovec | 0.11.5 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zerovec-derive | 0.11.2 | Unicode-3.0 | https://github.com/unicode-org/icu4x |
|
||||||
|
| zmij | 1.0.16 | MIT | https://github.com/dtolnay/zmij |
|
||||||
@ -83,7 +83,8 @@ impl RpcHandler {
|
|||||||
pub(super) async fn handle_fips_install(&self) -> Result<serde_json::Value> {
|
pub(super) async fn handle_fips_install(&self) -> Result<serde_json::Value> {
|
||||||
let identity_dir = fips::identity_dir_from(&self.config.data_dir);
|
let identity_dir = fips::identity_dir_from(&self.config.data_dir);
|
||||||
fips::config::install(&identity_dir).await?;
|
fips::config::install(&identity_dir).await?;
|
||||||
fips::service::activate(fips::SERVICE_UNIT).await?;
|
let unit = fips::service::activation_unit().await;
|
||||||
|
fips::service::activate(unit).await?;
|
||||||
let status = fips::FipsStatus::query(&self.config.data_dir).await;
|
let status = fips::FipsStatus::query(&self.config.data_dir).await;
|
||||||
Ok(serde_json::to_value(status)?)
|
Ok(serde_json::to_value(status)?)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,12 +56,12 @@ pub(in crate::api::rpc) async fn save_pending_seed_encrypted(
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best-effort: install fips.yaml + start archipelago-fips.service after the
|
/// Best-effort: install fips.yaml + start the available FIPS systemd unit after
|
||||||
/// seed onboarding has written the fips_key to disk. Runs in a detached task
|
/// seed onboarding has written the fips_key to disk. Runs in a detached task so
|
||||||
/// so the user-facing RPC returns immediately — the systemctl calls can take
|
/// the user-facing RPC returns immediately — the systemctl calls can take a few
|
||||||
/// a few seconds the first time on slow hardware. Any failure is logged but
|
/// seconds the first time on slow hardware. Any failure is logged but does not
|
||||||
/// does not break onboarding; the user can still hit fips.install manually
|
/// break onboarding; the user can still hit fips.install manually from the
|
||||||
/// from the dashboard as an escape hatch.
|
/// dashboard as an escape hatch.
|
||||||
fn spawn_post_onboarding_fips_activate(data_dir: std::path::PathBuf) {
|
fn spawn_post_onboarding_fips_activate(data_dir: std::path::PathBuf) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let identity_dir = data_dir.join("identity");
|
let identity_dir = data_dir.join("identity");
|
||||||
@ -78,11 +78,12 @@ fn spawn_post_onboarding_fips_activate(data_dir: std::path::PathBuf) {
|
|||||||
tracing::warn!("post-onboarding fips config install failed: {}", e);
|
tracing::warn!("post-onboarding fips config install failed: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Err(e) = crate::fips::service::activate(crate::fips::SERVICE_UNIT).await {
|
let unit = crate::fips::service::activation_unit().await;
|
||||||
tracing::warn!("post-onboarding archipelago-fips activate failed: {}", e);
|
if let Err(e) = crate::fips::service::activate(unit).await {
|
||||||
|
tracing::warn!("post-onboarding FIPS activate failed via {}: {}", unit, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::info!("archipelago-fips auto-activated post-onboarding");
|
tracing::info!("FIPS auto-activated post-onboarding via {}", unit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +139,8 @@ impl RpcHandler {
|
|||||||
// Initialize identity index at 0.
|
// Initialize identity index at 0.
|
||||||
crate::seed::save_identity_index(&self.config.data_dir, 0).await?;
|
crate::seed::save_identity_index(&self.config.data_dir, 0).await?;
|
||||||
|
|
||||||
// fips_key is now on disk — auto-activate archipelago-fips so the
|
// fips_key is now on disk — auto-activate FIPS so the user doesn't
|
||||||
// user doesn't have to hit an "Activate" button. Detached task;
|
// have to hit a manual Start button. Detached task;
|
||||||
// the onboarding RPC returns immediately.
|
// the onboarding RPC returns immediately.
|
||||||
spawn_post_onboarding_fips_activate(self.config.data_dir.clone());
|
spawn_post_onboarding_fips_activate(self.config.data_dir.clone());
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,8 @@ pub async fn ensure_activated(data_dir: &std::path::Path) {
|
|||||||
tracing::warn!("FIPS auto-activate: config install failed: {:#}", e);
|
tracing::warn!("FIPS auto-activate: config install failed: {:#}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Err(e) = service::activate(SERVICE_UNIT).await {
|
let unit = service::activation_unit().await;
|
||||||
|
if let Err(e) = service::activate(unit).await {
|
||||||
tracing::warn!("FIPS auto-activate: service activate failed: {:#}", e);
|
tracing::warn!("FIPS auto-activate: service activate failed: {:#}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,16 @@ pub async fn unit_state(unit: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether systemd knows about `unit`.
|
||||||
|
pub async fn unit_exists(unit: &str) -> bool {
|
||||||
|
Command::new("systemctl")
|
||||||
|
.args(["cat", unit])
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.map(|out| out.status.success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the `fips` debian package is installed on the host.
|
/// Whether the `fips` debian package is installed on the host.
|
||||||
pub async fn package_installed() -> bool {
|
pub async fn package_installed() -> bool {
|
||||||
// dpkg-query -W -f='${Status}' fips → "install ok installed" when present.
|
// dpkg-query -W -f='${Status}' fips → "install ok installed" when present.
|
||||||
@ -131,17 +141,28 @@ done
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve which systemd unit is actually supervising the fips daemon
|
/// Resolve which systemd unit should be started when FIPS is inactive.
|
||||||
/// on this host. Nodes installed from the archipelago ISO run
|
/// Newer Archipelago images may ship `archipelago-fips.service`; nodes with
|
||||||
/// `archipelago-fips.service`; nodes that were apt-installed (or had
|
/// the upstream Debian package may only have `fips.service`. Activation must
|
||||||
/// fips running before archipelago took over) may only have the
|
/// choose a unit systemd can actually load, otherwise the dashboard repeatedly
|
||||||
/// upstream `fips.service`. Restart/Reconnect must operate on whichever
|
/// offers an "Activate" action that can never succeed.
|
||||||
/// one is running, otherwise the UI button is a silent no-op.
|
pub async fn activation_unit() -> &'static str {
|
||||||
|
if unit_exists(super::SERVICE_UNIT).await {
|
||||||
|
return super::SERVICE_UNIT;
|
||||||
|
}
|
||||||
|
if unit_exists(super::UPSTREAM_SERVICE_UNIT).await {
|
||||||
|
return super::UPSTREAM_SERVICE_UNIT;
|
||||||
|
}
|
||||||
|
super::SERVICE_UNIT
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve which systemd unit is actually supervising the fips daemon on this
|
||||||
|
/// host. Restart/Reconnect must operate on whichever one is running, otherwise
|
||||||
|
/// the UI button is a silent no-op.
|
||||||
///
|
///
|
||||||
/// Returns the archipelago-managed unit name if it's active,
|
/// Returns the archipelago-managed unit name if it's active,
|
||||||
/// else the upstream unit name if that's active,
|
/// else the upstream unit name if that's active,
|
||||||
/// else the archipelago-managed name as a default (so activate() can
|
/// else a startable activation unit.
|
||||||
/// bring it up).
|
|
||||||
pub async fn active_unit() -> &'static str {
|
pub async fn active_unit() -> &'static str {
|
||||||
if unit_state(super::SERVICE_UNIT).await == "active" {
|
if unit_state(super::SERVICE_UNIT).await == "active" {
|
||||||
return super::SERVICE_UNIT;
|
return super::SERVICE_UNIT;
|
||||||
@ -149,7 +170,7 @@ pub async fn active_unit() -> &'static str {
|
|||||||
if unit_state(super::UPSTREAM_SERVICE_UNIT).await == "active" {
|
if unit_state(super::UPSTREAM_SERVICE_UNIT).await == "active" {
|
||||||
return super::UPSTREAM_SERVICE_UNIT;
|
return super::UPSTREAM_SERVICE_UNIT;
|
||||||
}
|
}
|
||||||
super::SERVICE_UNIT
|
activation_unit().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn mask(unit: &str) -> Result<()> {
|
pub async fn mask(unit: &str) -> Result<()> {
|
||||||
@ -248,4 +269,10 @@ mod tests {
|
|||||||
// Must not panic regardless of host state.
|
// Must not panic regardless of host state.
|
||||||
let _ = package_installed().await;
|
let _ = package_installed().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_unit_exists_is_bool() {
|
||||||
|
// Must not panic regardless of host state.
|
||||||
|
let _ = unit_exists("archipelago-bogus-test.service").await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -891,7 +891,7 @@ impl Server {
|
|||||||
// Post-onboarding auto-activation for archipelago-fips. Runs once
|
// Post-onboarding auto-activation for archipelago-fips. Runs once
|
||||||
// at startup: if fips_key is on disk, install /etc/fips/fips.yaml
|
// at startup: if fips_key is on disk, install /etc/fips/fips.yaml
|
||||||
// (schema-refreshed) and start the service. This removes the
|
// (schema-refreshed) and start the service. This removes the
|
||||||
// need for a user-facing "Activate" button — the node comes up
|
// need for a user-facing manual Start button — the node comes up
|
||||||
// with FIPS running whenever the seed has been onboarded. Also
|
// with FIPS running whenever the seed has been onboarded. Also
|
||||||
// self-heals legacy raw-byte fips.key files (load_fips_keys
|
// self-heals legacy raw-byte fips.key files (load_fips_keys
|
||||||
// rewrites them as bech32 nsec the first time they're read).
|
// rewrites them as bech32 nsec the first time they're read).
|
||||||
@ -940,14 +940,16 @@ impl Server {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Err(e) = crate::fips::service::activate(crate::fips::SERVICE_UNIT).await {
|
let unit = crate::fips::service::activation_unit().await;
|
||||||
|
if let Err(e) = crate::fips::service::activate(unit).await {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"archipelago-fips activate failed on startup: {} — user can retry via fips.install RPC",
|
"FIPS activate failed on startup via {}: {} — user can retry via fips.install RPC",
|
||||||
|
unit,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::info!("archipelago-fips auto-activated on startup");
|
tracing::info!("FIPS auto-activated on startup via {}", unit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,10 +1002,8 @@ impl Server {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let v6_task = if let Some(port) = v4_any_port {
|
let v6_task = if let Some(port) = v4_any_port {
|
||||||
let v6_addr = SocketAddr::new(
|
let v6_addr =
|
||||||
std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED),
|
SocketAddr::new(std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED), port);
|
||||||
port,
|
|
||||||
);
|
|
||||||
match bind_v6_only(v6_addr) {
|
match bind_v6_only(v6_addr) {
|
||||||
Ok(listener) => {
|
Ok(listener) => {
|
||||||
info!("IPv6 web listener bound {} (mesh ULA reachable)", v6_addr);
|
info!("IPv6 web listener bound {} (mesh ULA reachable)", v6_addr);
|
||||||
@ -1017,7 +1017,10 @@ impl Server {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("IPv6 web listener bind {} failed: {} — UI stays v4-only", v6_addr, e);
|
warn!(
|
||||||
|
"IPv6 web listener bind {} failed: {} — UI stays v4-only",
|
||||||
|
v6_addr, e
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1031,9 +1034,9 @@ impl Server {
|
|||||||
// IPv4 only for most apps, so a phone dialing [ULA]:8123 got
|
// IPv4 only for most apps, so a phone dialing [ULA]:8123 got
|
||||||
// nothing even with the firewall open (HA/FileBrowser/Gitea/
|
// nothing even with the firewall open (HA/FileBrowser/Gitea/
|
||||||
// Portainer/Pine all v4-only on 2026-07-26; a few bind [::]
|
// Portainer/Pine all v4-only on 2026-07-26; a few bind [::]
|
||||||
// themselves). Bridge each catalog launch port to its v4 loopback
|
// themselves). Bridge each catalog launch port on the fips0 ULA
|
||||||
// listener with a V6ONLY relay — self-selecting: where the app
|
// only. Binding wildcard [::]:port reserves the same host ports
|
||||||
// already answers on v6 the bind fails and the app wins.
|
// Podman needs and can restart-loop apps that publish those ports.
|
||||||
let relay_task = tokio::spawn(app_port_v6_relay_loop(tx.subscribe()));
|
let relay_task = tokio::spawn(app_port_v6_relay_loop(tx.subscribe()));
|
||||||
|
|
||||||
let peer_task = tokio::spawn(peer_late_bind_loop(
|
let peer_task = tokio::spawn(peer_late_bind_loop(
|
||||||
@ -1087,10 +1090,14 @@ fn bind_v6_only(addr: SocketAddr) -> std::io::Result<tokio::net::TcpListener> {
|
|||||||
tokio::net::TcpListener::from_std(socket.into())
|
tokio::net::TcpListener::from_std(socket.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fips_app_relay_addr(ip: std::net::Ipv6Addr, port: u16) -> SocketAddr {
|
||||||
|
SocketAddr::new(std::net::IpAddr::V6(ip), port)
|
||||||
|
}
|
||||||
|
|
||||||
/// IPv6→IPv4 relay for catalog app launch ports (see the spawn site for
|
/// IPv6→IPv4 relay for catalog app launch ports (see the spawn site for
|
||||||
/// why). Rescans every 60s so ports of freshly installed apps get bridged
|
/// why). Rescans every 60s so ports of freshly installed apps get bridged
|
||||||
/// without a daemon restart. Each relay is a V6ONLY listener forwarding
|
/// without a daemon restart. Each relay binds to the fips0 ULA only and
|
||||||
/// raw TCP to the same port on IPv4 loopback.
|
/// forwards raw TCP to the same port on IPv4 loopback.
|
||||||
async fn app_port_v6_relay_loop(mut shutdown_rx: tokio::sync::watch::Receiver<bool>) {
|
async fn app_port_v6_relay_loop(mut shutdown_rx: tokio::sync::watch::Receiver<bool>) {
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
let mut bridged: HashSet<u16> = HashSet::new();
|
let mut bridged: HashSet<u16> = HashSet::new();
|
||||||
@ -1099,6 +1106,7 @@ async fn app_port_v6_relay_loop(mut shutdown_rx: tokio::sync::watch::Receiver<bo
|
|||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = interval.tick() => {
|
_ = interval.tick() => {
|
||||||
|
let Some(fips_ip) = crate::fips::iface::fips0_ula() else { continue };
|
||||||
for &port in crate::fips::app_ports::APP_LAUNCH_PORTS {
|
for &port in crate::fips::app_ports::APP_LAUNCH_PORTS {
|
||||||
if bridged.contains(&port) {
|
if bridged.contains(&port) {
|
||||||
continue;
|
continue;
|
||||||
@ -1123,15 +1131,12 @@ async fn app_port_v6_relay_loop(mut shutdown_rx: tokio::sync::watch::Receiver<bo
|
|||||||
if !v4_up {
|
if !v4_up {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let addr = SocketAddr::new(
|
let addr = fips_app_relay_addr(fips_ip, port);
|
||||||
std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED),
|
// EADDRINUSE = fipsd or another process already answers
|
||||||
port,
|
// on this mesh address/port, so stay out of the way.
|
||||||
);
|
|
||||||
// EADDRINUSE = the app itself already answers on v6 —
|
|
||||||
// exactly when we must stay out of the way.
|
|
||||||
let Ok(listener) = bind_v6_only(addr) else { continue };
|
let Ok(listener) = bind_v6_only(addr) else { continue };
|
||||||
bridged.insert(port);
|
bridged.insert(port);
|
||||||
debug!("v6 relay bridging [::]:{port} -> 127.0.0.1:{port}");
|
debug!("v6 relay bridging [{fips_ip}]:{port} -> 127.0.0.1:{port}");
|
||||||
let mut rx = shutdown_rx.clone();
|
let mut rx = shutdown_rx.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
@ -1945,6 +1950,14 @@ mod merge_tests {
|
|||||||
assert!(!is_peer_allowed_path("/rpc/v2"));
|
assert!(!is_peer_allowed_path("/rpc/v2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn app_relay_binds_to_fips_ula_not_wildcard() {
|
||||||
|
let ula = "fd12:3456:789a::1".parse().unwrap();
|
||||||
|
let addr = fips_app_relay_addr(ula, 8083);
|
||||||
|
assert_eq!(addr.ip(), std::net::IpAddr::V6(ula));
|
||||||
|
assert_eq!(addr.port(), 8083);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn preserves_transitional_state_on_merge() {
|
fn preserves_transitional_state_on_merge() {
|
||||||
// existing: user initiated a stop, spawn_transitional set Stopping.
|
// existing: user initiated a stop, spawn_transitional set Stopping.
|
||||||
|
|||||||
9
demo/content/README.md
Normal file
9
demo/content/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Demo Content Provenance
|
||||||
|
|
||||||
|
All media in `demo/content/` and `demo/peer-media/` — music tracks, photos,
|
||||||
|
book covers, posters, and documents — are original works created and owned by
|
||||||
|
the Archipelago project author (Dorian), included here as demo content and
|
||||||
|
released with the project under the repository MIT license.
|
||||||
|
|
||||||
|
None of this content is sourced from third-party stock libraries or
|
||||||
|
commercial catalogs.
|
||||||
108
docs/LICENSE-COMPLIANCE-AUDIT.md
Normal file
108
docs/LICENSE-COMPLIANCE-AUDIT.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# License Compliance Audit — Open-Source Release
|
||||||
|
|
||||||
|
Audit date: 2026-07-22. Scope: entire repo (core Rust workspace, neode-ui, apps/*, Android companion, image-recipe ISO, docker/, app-catalog, reticulum-daemon, demo/) plus the external FIPS source and registry-mirrored images.
|
||||||
|
|
||||||
|
**Verdict:** the dependency graph is almost entirely permissive (MIT/Apache/BSD) and compatible with a free open-source release. But the repo is not releasable as-is: it has **no license of its own**, one **LGPL Rust dependency**, several **non-redistributable committed assets** (proprietary fonts, unknown-rights media), and **missing attribution machinery**. Everything below is ordered by severity.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## STATUS UPDATE — 2026-07-23
|
||||||
|
|
||||||
|
**DONE:**
|
||||||
|
- MIT adopted. Root `LICENSE` + `NOTICE` added; `license = "MIT"` in all 5 workspace crates (archy-fips-core already had it); `"license": "MIT"` (+ `"private": true`) in all 4 package.json files.
|
||||||
|
- Deleted: `Courier_New/`, `Benton_Sans/`, `Redacted/` fonts; `wireguard.apk`; `atob.s9pk`; obsolete `test-install.sh` (all git-rm'd; also removed from `web/dist`).
|
||||||
|
- Media provenance resolved: all demo music/photos/posters, UI sfx, backgrounds, and intro video are the author's original work — recorded in `demo/content/README.md` and `NOTICE`.
|
||||||
|
- Meshtastic device artwork attributed (`mesh-devices/ATTRIBUTION.md` + NOTICE); icon attribution added (`assets/icon/ATTRIBUTION.md`: game-icons.net CC BY 3.0, pixelarticons MIT).
|
||||||
|
- Reticulum decision: include + disclose (NOTICE states the Reticulum License restrictions and that it applies only to the optional daemon).
|
||||||
|
- indeedhub: deferred — partnership in place; license the submodule before/at public release.
|
||||||
|
- License inventories generated: `core/THIRD-PARTY-LICENSES.md` (649 crates) and `neode-ui/THIRD-PARTY-LICENSES.md` (runtime deps + fonts + vendored).
|
||||||
|
|
||||||
|
**REMAINING (code changes, awaiting review — see sections below for detail):**
|
||||||
|
1. Replace `zbase32` (LGPL-3.0+) with `z32` or original impl — §2.
|
||||||
|
2. Swap `redis:7.4.8` → Valkey in `scripts/image-versions.sh` and deploys — §3.
|
||||||
|
3. Delete dead StartOS-derived crates `core/{js-engine,container-init,models,helpers}` — §4.
|
||||||
|
4. Attribution build integration: cargo-about in CI → ship full license texts in ISO; vite/rollup license plugin (or UI licenses page) for the web bundle; Android OSS-licenses screen — §5.
|
||||||
|
5. Release-checklist items: per-release Debian source pointer (snapshot.debian.org), catalog `license`/`sourceUrl` fields, restrict ISO image bundling to the audited list — §6.
|
||||||
|
6. Before repo goes public: purge deleted fonts/APKs from git history (`git filter-repo`), and verify game-icons author credit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. BLOCKER — the project has no license
|
||||||
|
|
||||||
|
There is no `LICENSE`/`COPYING` file anywhere in the repo. No crate in `core/` declares a `license` field; none of the four `package.json` files do either (and the three `apps/*` packages aren't even `private: true`). Until fixed, the code is "all rights reserved" — publicly visible, but legally not open source and not usable by anyone.
|
||||||
|
|
||||||
|
**Do:**
|
||||||
|
- [ ] Choose a license. **Recommendation: MIT** — the Bitcoin-ecosystem norm (Bitcoin Core, LND are MIT), maximally compatible with everything found in the graph. (Alternatives: Apache-2.0 adds a patent grant; GPLv3 if copyleft is desired — nothing in the deps prevents any of these.)
|
||||||
|
- [ ] Add `LICENSE` at repo root with the year and copyright holder.
|
||||||
|
- [ ] Add `license = "MIT"` to all five workspace member `Cargo.toml`s (archipelago, container, openwrt, performance, security) and `Android/rust/archy-fips-core` (declares MIT but ships no license file — add one).
|
||||||
|
- [ ] Add `"license": "MIT"` to `neode-ui/package.json` and `apps/{morphos-server,router,did-wallet}/package.json`.
|
||||||
|
|
||||||
|
## 2. BLOCKER — copyleft dependency that must be replaced
|
||||||
|
|
||||||
|
- [ ] **`zbase32 0.1.2` — LGPL-3.0+** — the only hard copyleft blocker in all 649 resolved Rust crates. Direct dep of `archipelago`, used in `core/archipelago/src/network/did_dht.rs` for did:dht z-base-32 encoding. LGPL statically linked into a Rust binary requires shipping relinkable objects/source — impractical. **Replace with the MIT `z32` crate** or a ~30-line original alphabet-substitution implementation.
|
||||||
|
|
||||||
|
No GPL, AGPL, SSPL, or unlicensed crates exist anywhere else in the Rust graph. (`r-efi` and `self_cell` list LGPL/GPL only as options in OR-expressions — elect MIT/Apache, no action.)
|
||||||
|
|
||||||
|
## 3. BLOCKER — committed files we may not redistribute
|
||||||
|
|
||||||
|
Remove from git (and **purge from history** before the repo goes public — they're in past commits):
|
||||||
|
|
||||||
|
- [ ] `neode-ui/public/assets/fonts/Courier_New/` — Monotype proprietary font, no license, **unused in CSS**. Delete.
|
||||||
|
- [ ] `neode-ui/public/assets/fonts/Benton_Sans/BentonSans-Regular.otf` — commercial Font Bureau typeface, no license, unused. Delete.
|
||||||
|
- [ ] `neode-ui/public/packages/wireguard.apk` (17 MB) — official WireGuard Android APK containing GPL-2.0 `libwg` components; redistribution triggers GPL source-offer. **Unreferenced since the FIPS migration** — delete.
|
||||||
|
- [ ] `neode-ui/public/packages/atob.s9pk` (24 MB) — Start9 service package, unknown license, referenced only by a test script. Delete.
|
||||||
|
- [ ] `demo/content/music/` (18 full tracks, ~150 MB) and `demo/peer-media/` (17 photos/book covers/film posters) — no recorded rights. If they're your own/AI-generated work, document that in a `demo/content/README`; otherwise remove.
|
||||||
|
- [ ] `neode-ui/public/assets/video/video-intro.mp4`, `Kratter.MP3`, photographic `bg-*.jpg` backgrounds, UI/arcade sound effects in `assets/audio/` — same: document provenance (user-made per project convention) or replace. `welcome-noderunner.mp3` is ElevenLabs TTS — their commercial-use terms allow this on paid plans; note it.
|
||||||
|
- [ ] **Registry: `redis:7.4.8`** (`scripts/image-versions.sh` `REDIS_IMAGE`) — Redis ≥ 7.4 is RSALv2/SSPLv1, **not open source**; re-hosting it on your registry is redistribution under a restricted license. **Switch to Valkey** (BSD-3, already mirrored) everywhere.
|
||||||
|
|
||||||
|
## 4. VERIFY — unknown/third-party provenance
|
||||||
|
|
||||||
|
- [ ] **`neode-ui/public/assets/img/mesh-devices/` (36 SVGs)** — almost certainly Meshtastic project device artwork (meshtastic/web is GPL-3.0). Confirm source; either replace with original art or comply with the upstream license + attribution.
|
||||||
|
- [ ] **`neode-ui/public/assets/icon/`** — `barbarian.svg`, `batteries.svg` match game-icons.net (**CC BY 3.0 — visible attribution required**); pixel-style icons match pixelarticons (MIT). Confirm and add attribution, or replace.
|
||||||
|
- [ ] `Redacted/redacted.regular.ttf` — upstream is SIL OFL 1.1 but no license file is shipped. Add `OFL.txt` or delete (unused).
|
||||||
|
- [ ] **indeedhub** — submodule (private gitea) not checked out; no known license, yet `indeedhub{,-api,-ffmpeg}:1.0.0` images are distributed via registry/ISO. `indeedhub-ffmpeg` implies a bundled FFmpeg (LGPL/GPL → source-offer obligations). Must license the project and audit the ffmpeg build before public release.
|
||||||
|
- [ ] `minmoto/fmcd` v0.8.0 and `ark-bitcoin/bark` (barkd) — binaries redistributed in your images; verify upstream licenses (bark claims Apache-2.0/MIT dual) and include their notices.
|
||||||
|
- [ ] **Start9/StartOS heritage** — `core/{js-engine,container-init,models,helpers}` are StartOS-derived (embassy paths, s9pk handling). start-os is MIT → attribution required if kept. **Better: delete these four crates** — they are not workspace members, cannot compile (broken `../../patch-db` path dep), and carry an unpinned `yajrc = "*"` git dep on a moving branch. Deleting removes both the attribution question and dead code.
|
||||||
|
- [ ] **Reticulum (RNS 1.3.5 + LXMF)** — verified: custom "Reticulum License" — MIT-style **plus field-of-use restrictions** (no systems designed to harm humans; no AI/ML training-dataset use). Redistribution is permitted, so shipping the PyInstaller `archy-reticulum-daemon` binary is fine **if** the license text is included with it — but the OS cannot claim to be 100 % OSI-open-source while bundling it. Options: include + disclose (recommended, matches "plan for decentralization" honesty), or make the daemon an optional download.
|
||||||
|
|
||||||
|
## 5. REQUIRED — attribution / notice machinery (currently absent)
|
||||||
|
|
||||||
|
Nearly every permissive license (MIT/BSD/ISC/Apache) requires reproducing copyright + license text **in distributed binaries** — and right now every distribution channel strips them:
|
||||||
|
|
||||||
|
- [ ] **Rust binaries** (649 crates, ~85 % MIT/Apache dual): generate `THIRD-PARTY-LICENSES` with `cargo-about` (or `cargo-license`) in CI; ship it in the ISO at e.g. `/usr/share/doc/archipelago/`. Include **ring's three license files** (LICENSE, LICENSE-BoringSSL, LICENSE-other-bits) and note the system OpenSSL (Apache-2.0) linked via `ssh2`.
|
||||||
|
- [ ] **Web bundle**: Vite/esbuild strips all `@license` comments from `web/dist`. Add `rollup-plugin-license`/`vite-plugin-license` to emit a third-party attribution file, or add an "Open-source licenses" page in the UI. Runtime deps needing notices: vue/vue-router/pinia/vue-i18n (MIT), d3 (ISC), leaflet (BSD-2), dompurify (elect Apache-2.0 of its MPL/Apache dual), fuse.js (Apache-2.0), qrcode/qr-scanner/qrloop/buffer/fast-json-patch (MIT).
|
||||||
|
- [ ] **Android APK**: `packaging.excludes` strips `META-INF` license texts and there is no licenses screen. Add an OSS-licenses screen or bundled `licenses.txt` covering AndroidX/Compose/OkHttp/ZXing (Apache-2.0), **fips © 2026 Johnathan Corgan (MIT — the core of the VPN feature)**, tokio/tracing (MIT), subtle (BSD-3), tun (WTFPL — permissive, just list it), secp256k1 family (CC0). Generate the Rust side from the committed `Cargo.lock` with cargo-about.
|
||||||
|
- [ ] **AIUI demo bundle** (`demo/aiui/` — committed minified build): bundles Mermaid, Cytoscape, KaTeX, D3, Lodash, Workbox (all MIT/BSD). Add a `THIRD-PARTY-LICENSES` file next to it (or rebuild with a license plugin).
|
||||||
|
- [ ] Keep the intact MIT headers in the two vendored `qrcode.js` copies (docker/lnd-ui, docker/electrs-ui) — already compliant, don't minify them.
|
||||||
|
- [ ] Fonts kept: Montserrat (OFL.txt present ✓), Open Sans (Apache LICENSE.txt present ✓) — keep license files adjacent to the font files in dist.
|
||||||
|
|
||||||
|
## 6. REQUIRED — distribution-level obligations (ISO & registry)
|
||||||
|
|
||||||
|
The ISO redistributes a full Debian (trixie) system plus ~29 container image tarballs; the private registry re-hosts upstream images. Re-hosting = redistribution, same obligations as bundling.
|
||||||
|
|
||||||
|
- [ ] **GPL source offer for the ISO** — kernel, GRUB, busybox/live-boot, coreutils, nftables, cryptsetup, wireguard-tools, SYSLINUX `isohdpfx.bin`, etc. Easiest compliance: keep `/usr/share/doc/*/copyright` (the build already does ✓) **and** publish, per release, either a mirror of the exact Debian source packages (`apt-get source` snapshot / snapshot.debian.org pointer) or a written offer in the docs. Add this to the release checklist.
|
||||||
|
- [ ] **AGPLv3 images redistributed** (mempool, Grafana, Vaultwarden, SearXNG, PhotoPrism, Nextcloud, Immich, CryptPad, MinIO): AGPL compliance = make corresponding source available. You ship a **modified** mempool-frontend (`docker/mempool-frontend` entrypoint patch) — the patch is in-repo, so compliance is met once the repo is public; state this in docs. For unmodified images, link upstream sources in the app catalog.
|
||||||
|
- [ ] **GPLv2/GPLv3 images** (MariaDB, Jellyfin, AdGuard Home, strfry): unmodified redistribution → provide license text + upstream source links (a `license` + `sourceUrl` field per `app-catalog/catalog.json` entry solves this catalog-wide).
|
||||||
|
- [ ] **Non-free firmware** (firmware-realtek/iwlwifi/misc/linux-nonfree, intel/amd microcode): redistributable but proprietary — disclose in docs ("includes non-free firmware for hardware support"), like Debian's own non-free-firmware ISOs do.
|
||||||
|
- [ ] The ISO build's live-server image capture (`podman save` of whatever matches on the dev server) is a compliance hazard — bundle only from the audited image list.
|
||||||
|
- [ ] FIPS daemon (jmcorgan/fips v0.4.1, MIT ✓) and nostr-rs-relay binary (MIT ✓): include their license texts in the notices bundle.
|
||||||
|
|
||||||
|
## 7. Housekeeping (supports compliance)
|
||||||
|
|
||||||
|
- [ ] Add lockfiles + pinned versions in `apps/*` (currently floating `^` ranges, violating the project's own pinning rule) — reproducibility is also what makes license audits stay true.
|
||||||
|
- [ ] `Android` fips dep is pinned to a personal fork rev (`9qeklajc/fips-native@46494a74`) — mirror or vendor it so outside contributors can build.
|
||||||
|
- [ ] Move `@types/dompurify` to devDeps; refresh stale `neode-ui/node_modules`.
|
||||||
|
- [ ] Add a `NOTICE` file at root naming: fips (Johnathan Corgan, MIT), Start9 start-os (if any derived code remains), Kazuhiko Arase qrcode.js, font licenses, icon attributions.
|
||||||
|
- [ ] Consider CI license gating: `cargo-deny` (Rust) + `license-checker` (npm) with an allowlist, so new copyleft deps are caught at PR time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick reference: what's already clean
|
||||||
|
|
||||||
|
- All 649 Rust crates except `zbase32`: permissive or dual-licensed.
|
||||||
|
- All 833 npm packages in neode-ui: no GPL/AGPL anywhere; only dev-tool LGPL (sharp's libvips, never distributed).
|
||||||
|
- Android Gradle deps: 100 % Apache-2.0, all pinned, no Play Services/telemetry.
|
||||||
|
- FIPS mesh: MIT (© 2026 Johnathan Corgan) — keep notice.
|
||||||
|
- js-engine binds deno_core (MIT) as a crate, nothing vendored — moot if dead crates are deleted.
|
||||||
|
- reticulum-daemon Python is original code; obligations attach only to the PyInstaller binary (see §4).
|
||||||
|
- Bitcoin Core/Knots, LND, BTCPay, Electrs, Fedimint, core-lightning, Gitea, Home Assistant, Tailscale, Portainer, Uptime-Kuma, filebrowser, ollama, penpot: MIT/Apache/BSD/Zlib/MPL — link + notice is enough.
|
||||||
@ -27,6 +27,75 @@ is GREEN and must stay green. Re-run after any orchestrator/lifecycle change (Ph
|
|||||||
especially). All cargo verification uses `--all-features` to match CI. Stage by explicit
|
especially). All cargo verification uses `--all-features` to match CI. Stage by explicit
|
||||||
path, never `git add -A` (shared tree).
|
path, never `git add -A` (shared tree).
|
||||||
|
|
||||||
|
## Current local pass status
|
||||||
|
|
||||||
|
This branch is replayed on top of `origin/main` as `public-prelaunch`.
|
||||||
|
|
||||||
|
Completed locally in this pass:
|
||||||
|
|
||||||
|
- Redacted the two tracked Anthropic API key literals from
|
||||||
|
`scripts/setup-aiui-server.sh` and
|
||||||
|
`image-recipe/_archived/build-auto-installer-iso.sh`.
|
||||||
|
- Removed `Android/app/debug.keystore` and `core/.env.production` from the
|
||||||
|
source tree; copies were preserved in
|
||||||
|
`~/Desktop/archipelago-sensitive-backup-2026-07-27/`.
|
||||||
|
- Reworked `scripts/audit-secrets.sh` to scan tracked source more aggressively
|
||||||
|
and to catch non-example env files and credential file patterns.
|
||||||
|
- Reworked `scripts/validate-app-manifest.sh` so the current `app:` manifest
|
||||||
|
schema can be audited without a Python `PyYAML` dependency.
|
||||||
|
- Updated root/community docs, CI, PR template, app developer notes, and
|
||||||
|
container/deployment docs toward public contributor expectations.
|
||||||
|
- Fixed native FIPS activation fallback: nodes that have the packaged
|
||||||
|
`fips.service` but not `archipelago-fips.service` now start the available
|
||||||
|
unit instead of repeatedly failing activation against a missing unit. This
|
||||||
|
now covers startup, supervisor self-heal, manual dashboard start/reconnect,
|
||||||
|
and post-onboarding activation. The UI now labels the action as `Start`
|
||||||
|
instead of making native FIPS look like an installable app.
|
||||||
|
- Fixed the FIPS app-port relay design so it binds relays to the node's FIPS
|
||||||
|
ULA instead of wildcard `[::]`, avoiding collisions with Podman-published app
|
||||||
|
ports such as FileBrowser `8083` and Botfights `9100`.
|
||||||
|
- Added `docs/nostr-git-source-hosting.md`, a NIP-34/ngit/GRASP source hosting
|
||||||
|
plan using a Bitcoin Core-style maintainer model: public review and easy
|
||||||
|
forks, with canonical merge rights held by a small signed maintainer set.
|
||||||
|
|
||||||
|
Verified locally:
|
||||||
|
|
||||||
|
- `./scripts/audit-secrets.sh` passes.
|
||||||
|
- Full `apps/*/manifest.yml` repository audit passes with warnings only.
|
||||||
|
- `bash -n` passes for the edited shell scripts.
|
||||||
|
- Targeted FIPS dashboard vitest passes.
|
||||||
|
- Targeted Rust tests for FIPS service unit detection and FIPS app relay
|
||||||
|
address selection pass.
|
||||||
|
|
||||||
|
Verified on a Linux Archipelago verification node:
|
||||||
|
|
||||||
|
- Native FIPS was restored by starting the already-installed packaged
|
||||||
|
`fips.service`; the daemon became active and joined the FIPS tree.
|
||||||
|
- Correct local lifecycle API endpoint is HTTP, not HTTPS
|
||||||
|
(`ARCHY_HOST=127.0.0.1 ARCHY_SCHEME=http`).
|
||||||
|
- Read-only lifecycle run progressed past login and confirmed required
|
||||||
|
containers, Bitcoin RPC, ElectrumX TCP, and manifest port-drift checks, but
|
||||||
|
did not complete cleanly: `botfights` and `filebrowser` remained in
|
||||||
|
`restarting` longer than the matrix window, and the LND `lncli getinfo`
|
||||||
|
probe hung. Do not run the destructive gate until those live-node issues are
|
||||||
|
understood.
|
||||||
|
- After the node updated to `1.7.116-alpha`, `botfights`, `filebrowser`, and
|
||||||
|
`lnd` were active/running and ports `8083`/`9100` were held by Podman's
|
||||||
|
`rootlessport` as expected. The packaged `fips.service` remained installed
|
||||||
|
and enabled but inactive, so the native FIPS service fallback should still
|
||||||
|
ship before the public launch.
|
||||||
|
|
||||||
|
Still required before public publish:
|
||||||
|
|
||||||
|
- Rotate/revoke compromised credentials listed in Phase 0.
|
||||||
|
- Finish Phase 1 password/node/token sanitization beyond the two API keys.
|
||||||
|
- Publish from fresh history after the sanitized tree is final.
|
||||||
|
- Run full Rust, frontend, Android, and lifecycle gate verification.
|
||||||
|
- Resolve the live-node lifecycle blockers above, then rerun the read-only
|
||||||
|
suite followed by the destructive gate only on an approved verification node.
|
||||||
|
- Decide the canonical Archipelago maintainer npub and merge-maintainer npub
|
||||||
|
list before publishing the Nostr Git source-hosting workflow.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 0 — Credential rotation (immediate, independent of the repo)
|
## Phase 0 — Credential rotation (immediate, independent of the repo)
|
||||||
|
|||||||
@ -146,7 +146,7 @@ app:
|
|||||||
path: /health
|
path: /health
|
||||||
interfaces:
|
interfaces:
|
||||||
main:
|
main:
|
||||||
type: web
|
type: ui
|
||||||
port: 8090
|
port: 8090
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -74,9 +74,10 @@ archy/
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- **macOS** (development machine): Node.js 20+, npm
|
- Node.js 20+ and npm for frontend development.
|
||||||
- **Linux server** (`192.168.1.228`): Rust toolchain, Podman, Nginx, Debian 13
|
- Rust stable for backend development.
|
||||||
- SSH key: `~/.ssh/archipelago-deploy`
|
- Linux with Podman, systemd, and Nginx for host integration work.
|
||||||
|
- Debian 13 is the target runtime for release validation.
|
||||||
|
|
||||||
### Local Frontend Development
|
### Local Frontend Development
|
||||||
|
|
||||||
@ -86,17 +87,18 @@ npm install
|
|||||||
npm start # Vite dev server on :8100, mock backend on :5959
|
npm start # Vite dev server on :8100, mock backend on :5959
|
||||||
```
|
```
|
||||||
|
|
||||||
The dev server at `http://localhost:8100` uses a mock backend. Login with `password123`.
|
The dev server at `http://localhost:8100` uses a mock backend.
|
||||||
|
|
||||||
### Deploying Changes
|
### Deploying Changes
|
||||||
|
|
||||||
**Never build Rust on macOS.** The deploy script rsyncs source to the Linux server and builds there.
|
Release and host-integration builds should run on Linux. The deploy script rsyncs
|
||||||
|
source to a configured Linux target and builds there.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Deploy to live server (builds backend + frontend, restarts services)
|
# Deploy to the configured primary target (builds backend + frontend, restarts services)
|
||||||
./scripts/deploy-to-target.sh --live
|
./scripts/deploy-to-target.sh --live
|
||||||
|
|
||||||
# Deploy to both servers
|
# Deploy to both configured targets
|
||||||
./scripts/deploy-to-target.sh --both
|
./scripts/deploy-to-target.sh --both
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -114,14 +116,16 @@ The deploy script:
|
|||||||
# Frontend tests
|
# Frontend tests
|
||||||
cd neode-ui && npm test
|
cd neode-ui && npm test
|
||||||
|
|
||||||
# Backend tests (on dev server via SSH)
|
# Backend tests
|
||||||
ssh -i ~/.ssh/archipelago-deploy archipelago@192.168.1.228 \
|
cd core && cargo test --all-features
|
||||||
"cd ~/archy/core && cargo test --all-features"
|
|
||||||
|
|
||||||
# Both
|
# Both
|
||||||
./scripts/run-tests.sh
|
./scripts/run-tests.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`scripts/run-tests.sh` can run backend tests on a Linux target when
|
||||||
|
`ARCHIPELAGO_SSH_HOST` and `ARCHIPELAGO_SSH_KEY` are set.
|
||||||
|
|
||||||
## Adding a New RPC Endpoint
|
## Adding a New RPC Endpoint
|
||||||
|
|
||||||
### 1. Create the Handler
|
### 1. Create the Handler
|
||||||
@ -200,7 +204,7 @@ async myAction(params: { name: string }): Promise<{ ok: boolean; result: string
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/deploy-to-target.sh --live
|
./scripts/deploy-to-target.sh --live
|
||||||
curl -X POST http://192.168.1.228/rpc/v1 \
|
curl -X POST http://<node-host>/rpc/v1 \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-b "archipelago_session=YOUR_SESSION" \
|
-b "archipelago_session=YOUR_SESSION" \
|
||||||
-d '{"method":"mymodule.action","params":{"name":"test"}}'
|
-d '{"method":"mymodule.action","params":{"name":"test"}}'
|
||||||
@ -309,5 +313,5 @@ mod tests {
|
|||||||
2. Make changes following the standards above
|
2. Make changes following the standards above
|
||||||
3. Test locally: `cd neode-ui && npm test`
|
3. Test locally: `cd neode-ui && npm test`
|
||||||
4. Deploy to dev server: `./scripts/deploy-to-target.sh --live`
|
4. Deploy to dev server: `./scripts/deploy-to-target.sh --live`
|
||||||
5. Verify at `http://192.168.1.228`
|
5. Verify on your configured development target
|
||||||
6. Commit with conventional format: `feat: add my feature`
|
6. Commit with conventional format: `feat: add my feature`
|
||||||
|
|||||||
252
docs/nostr-git-source-hosting.md
Normal file
252
docs/nostr-git-source-hosting.md
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
# Nostr Git Source Hosting Plan
|
||||||
|
|
||||||
|
This plan describes how Archipelago can publish and accept contributions to its
|
||||||
|
source code through `ngit`, NIP-34, and GRASP while keeping the developer
|
||||||
|
experience inside Archipelago.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Publish Archipelago source from a sanitized, fresh-history repository.
|
||||||
|
- Make the in-app registry the primary onboarding path for contributors.
|
||||||
|
- Let contributors clone, branch, push PR branches, open PRs, and discuss issues
|
||||||
|
with a Nostr identity from their Archipelago node.
|
||||||
|
- Follow the Bitcoin Core development model: broad public review and easy forks,
|
||||||
|
with canonical merge authority held by a small maintainer set.
|
||||||
|
- Give contributors full read, fork, and proposal rights, but no direct merge
|
||||||
|
rights on the canonical repository.
|
||||||
|
- Keep the official maintainer identity and merge authority separate from user
|
||||||
|
node identities.
|
||||||
|
|
||||||
|
## Current Building Blocks
|
||||||
|
|
||||||
|
Archipelago already has most of the primitives needed for this:
|
||||||
|
|
||||||
|
- App manifests and the app registry already install developer tooling as
|
||||||
|
rootless Podman apps.
|
||||||
|
- The `gitea` app provides a conventional fallback Git UI and package registry.
|
||||||
|
- The app launcher already exposes a consent-gated NIP-07 bridge for launched
|
||||||
|
apps using `getPublicKey`, `signEvent`, NIP-04, and NIP-44 requests.
|
||||||
|
- The backend exposes node and identity Nostr signing RPC methods.
|
||||||
|
- FIPS gives nodes a stable mesh identity and private transport path, but repo
|
||||||
|
announcements and PRs should remain NIP-34 compatible on normal Nostr relays.
|
||||||
|
- DWN protocol registration exists and can be used later for local contribution
|
||||||
|
metadata/cache, but should not be required for the first public workflow.
|
||||||
|
|
||||||
|
## Protocol Basis
|
||||||
|
|
||||||
|
Use existing Nostr Git conventions rather than inventing an Archipelago-only
|
||||||
|
protocol:
|
||||||
|
|
||||||
|
- NIP-34 repository announcement events identify repositories with kind `30617`.
|
||||||
|
- NIP-34 repository state events publish branch/tag refs with kind `30618`.
|
||||||
|
- NIP-34 patches, pull requests, PR updates, issues, and status events use kinds
|
||||||
|
`1617`, `1618`, `1619`, `1621`, and `1630`-`1633`.
|
||||||
|
- `ngit` provides the `git-remote-nostr` helper for `nostr://` clone URLs and PR
|
||||||
|
branches.
|
||||||
|
- GRASP servers provide Git Smart HTTP storage while Nostr events remain the
|
||||||
|
authority for repository identity, refs, PRs, issues, and maintainer state.
|
||||||
|
|
||||||
|
Primary references:
|
||||||
|
|
||||||
|
- https://nips.nostr.com/34
|
||||||
|
- https://docs.rs/crate/ngit/latest/source/README.md
|
||||||
|
- https://ngit.dev/grasp/
|
||||||
|
|
||||||
|
## Recommended Architecture
|
||||||
|
|
||||||
|
### Apps
|
||||||
|
|
||||||
|
Create two first-party apps:
|
||||||
|
|
||||||
|
- `ngit`: CLI/runtime package containing `ngit` and `git-remote-nostr`.
|
||||||
|
- `archipelago-source`: web UI for cloning Archipelago source, viewing NIP-34
|
||||||
|
issues/PRs, opening branches, and submitting PR events.
|
||||||
|
|
||||||
|
The `archipelago-source` app should depend on `ngit`. It can also recommend
|
||||||
|
Gitea for users who want a conventional local web Git UI, but Gitea should not
|
||||||
|
be the source of truth for public contribution permissions.
|
||||||
|
|
||||||
|
### Contributor Onboarding
|
||||||
|
|
||||||
|
When the user installs `archipelago-source` from the registry:
|
||||||
|
|
||||||
|
1. Show a modal before first launch: "Contribute to Archipelago".
|
||||||
|
2. Explain that the app will use their Archipelago Nostr identity to clone and
|
||||||
|
sign contribution events.
|
||||||
|
3. Display the maintainer repository announcement, clone URL, maintainer npub,
|
||||||
|
and relay/GRASP endpoints.
|
||||||
|
4. Ask for consent to:
|
||||||
|
- fetch repository metadata from configured relays,
|
||||||
|
- clone source through `nostr://`,
|
||||||
|
- create local branches,
|
||||||
|
- sign NIP-34 issue/PR/comment events,
|
||||||
|
- push PR branches to approved GRASP servers.
|
||||||
|
5. Store approval per app origin, identity id, repository id, and relay set.
|
||||||
|
|
||||||
|
This should build on the existing NIP-07 app-launcher bridge, but use a more
|
||||||
|
specific permission scope than the generic sign-event approval.
|
||||||
|
|
||||||
|
### Identity And Permissions
|
||||||
|
|
||||||
|
Use four identity classes:
|
||||||
|
|
||||||
|
- `archipelago-maintainer`: an offline or tightly controlled Nostr key that
|
||||||
|
signs the canonical kind `30617` repo announcement and status/merge events.
|
||||||
|
- `archipelago-merge-maintainer`: one of the small set of maintainer npubs
|
||||||
|
allowed to advance canonical refs and publish valid merged/applied status.
|
||||||
|
- `archipelago-build`: release automation key for signed release artifacts and
|
||||||
|
CI status events. It must not have merge authority.
|
||||||
|
- `contributor`: user node or app-specific identity used for PRs, issues, and
|
||||||
|
comments.
|
||||||
|
|
||||||
|
Contributor rights:
|
||||||
|
|
||||||
|
- Clone the repository.
|
||||||
|
- Open issues.
|
||||||
|
- Push proposal branches using `pr/<npub>/<short-topic>` or `pr/<event-id>`.
|
||||||
|
- Publish NIP-34 PR/update/comment events.
|
||||||
|
- Rebase and update their own PR branch.
|
||||||
|
- Run local validation and attach status evidence.
|
||||||
|
|
||||||
|
Contributor restrictions:
|
||||||
|
|
||||||
|
- Cannot update `refs/heads/main` or release branches in canonical state.
|
||||||
|
- Cannot publish maintainer-valid merge/applied status.
|
||||||
|
- Cannot alter the canonical repository announcement.
|
||||||
|
- Cannot publish release catalog signatures.
|
||||||
|
|
||||||
|
Maintainer rights:
|
||||||
|
|
||||||
|
- Publish/update the canonical repo announcement.
|
||||||
|
- Publish canonical `refs/heads/main` state.
|
||||||
|
- Mark PRs merged/closed/draft via NIP-34 status events.
|
||||||
|
- Sign release tags and catalog updates.
|
||||||
|
|
||||||
|
Fork rights:
|
||||||
|
|
||||||
|
- Any contributor can create their own NIP-34 kind `30617` repository
|
||||||
|
announcement for a fork.
|
||||||
|
- Fork announcements should use the NIP-34 `u` tag to point back to the
|
||||||
|
canonical `archy` repository.
|
||||||
|
- The source app should make forking a first-class path: "Fork on Nostr", clone
|
||||||
|
the fork locally, push branches to the contributor's GRASP list, and open PRs
|
||||||
|
back to canonical Archipelago when they want review.
|
||||||
|
- Forks can have their own maintainer npubs, relays, policies, and release
|
||||||
|
cadence, but the app should clearly label them as forks unless signed by the
|
||||||
|
canonical maintainer set.
|
||||||
|
|
||||||
|
The GRASP server policy should enforce this by accepting pushes to maintainer
|
||||||
|
refs only when backed by signed maintainer state, while allowing contributor PR
|
||||||
|
refs from their own npubs.
|
||||||
|
|
||||||
|
## Repository Layout
|
||||||
|
|
||||||
|
Canonical repo announcement:
|
||||||
|
|
||||||
|
- repo id: `archy`
|
||||||
|
- display name: `Archipelago`
|
||||||
|
- clone URLs:
|
||||||
|
- `nostr://<maintainer-npub>/<relay-hint>/archy`
|
||||||
|
- `https://<grasp-host>/<maintainer-npub>/archy.git`
|
||||||
|
- relays:
|
||||||
|
- Archipelago-operated relay
|
||||||
|
- at least two public Nostr relays that support the event load
|
||||||
|
- GRASP servers:
|
||||||
|
- Archipelago-operated GRASP instance
|
||||||
|
- one public GRASP-compatible mirror
|
||||||
|
|
||||||
|
Keep the existing HTTP Git remote as a mirror during launch. The docs can
|
||||||
|
present `nostr://` as the preferred contribution path once the workflow is
|
||||||
|
proven.
|
||||||
|
|
||||||
|
## UI Requirements
|
||||||
|
|
||||||
|
The source app should provide:
|
||||||
|
|
||||||
|
- A first-run contribution modal with a real Archipelago source graphic, not a
|
||||||
|
generic text-only dialog.
|
||||||
|
- Current clone status and local path.
|
||||||
|
- Branch list, changed files, commit form, and push/open-PR flow.
|
||||||
|
- PR inbox, issue list, maintainer status, and relay health.
|
||||||
|
- Explicit identity indicator showing which npub will sign events.
|
||||||
|
- A merge rights indicator that clearly says contributors can propose changes
|
||||||
|
but cannot merge them.
|
||||||
|
- A fork flow that creates a user-owned NIP-34 repo announcement and remote,
|
||||||
|
then offers "Open PR to Archipelago" from any fork branch.
|
||||||
|
- Maintainer badges based only on pinned canonical maintainer npubs, not relay
|
||||||
|
metadata or server-side account names.
|
||||||
|
- Links to container docs, deployment docs, manifest spec, and open-source
|
||||||
|
readiness tasks.
|
||||||
|
|
||||||
|
## Backend Work
|
||||||
|
|
||||||
|
Add an RPC module for source contribution workflow:
|
||||||
|
|
||||||
|
- `source.repo-info`: returns canonical announcement, clone URL, relay set,
|
||||||
|
maintainer npubs, and local clone state.
|
||||||
|
- `source.ensure-ngit`: verifies the `ngit` app/runtime is installed.
|
||||||
|
- `source.clone`: clones or updates the local source checkout.
|
||||||
|
- `source.status`: returns branch, dirty files, ahead/behind, and PR state.
|
||||||
|
- `source.commit`: creates a local commit from selected files.
|
||||||
|
- `source.fork`: creates a contributor-owned NIP-34 fork announcement and local
|
||||||
|
remote.
|
||||||
|
- `source.open-pr`: pushes a PR branch and publishes a kind `1618` event.
|
||||||
|
- `source.update-pr`: updates the branch and publishes kind `1619`.
|
||||||
|
- `source.issue`: publishes a kind `1621` event.
|
||||||
|
|
||||||
|
Backend must shell out through a narrow command wrapper, never arbitrary user
|
||||||
|
commands. The wrapper should set an isolated working tree under
|
||||||
|
`/var/lib/archipelago/source/archy`, run as the Archipelago service user, and
|
||||||
|
deny operations outside that path.
|
||||||
|
|
||||||
|
## Security Model
|
||||||
|
|
||||||
|
- Never expose maintainer private keys to an Archipelago node.
|
||||||
|
- Prefer app-specific contributor identities over the node's default identity.
|
||||||
|
- Require per-action consent for first PR push, issue creation, and signing any
|
||||||
|
event that tags the canonical repository.
|
||||||
|
- Pin the canonical maintainer npub in the app manifest and backend config.
|
||||||
|
- Keep the canonical merge-maintainer allow list signed by the
|
||||||
|
`archipelago-maintainer` key; never infer merge rights from GRASP server
|
||||||
|
accounts.
|
||||||
|
- Verify the canonical kind `30617` event signature before displaying clone
|
||||||
|
instructions.
|
||||||
|
- Treat GRASP servers as untrusted storage; verify Git refs against signed
|
||||||
|
Nostr state.
|
||||||
|
- Do not use destructive git operations from the UI without an explicit modal.
|
||||||
|
- Store local clones and generated patches outside app container writable roots
|
||||||
|
unless the user exports them.
|
||||||
|
|
||||||
|
## MVP
|
||||||
|
|
||||||
|
1. Package `ngit` as a first-party app.
|
||||||
|
2. Stand up one Archipelago-operated GRASP server and one Nostr relay.
|
||||||
|
3. Publish sanitized fresh-history `archy` through `ngit init`.
|
||||||
|
4. Add a simple `archipelago-source` app that clones source and links out to the
|
||||||
|
preferred Nostr Git browser.
|
||||||
|
5. Add app-launcher consent scopes for repository-specific NIP-34 signing.
|
||||||
|
6. Allow issues and PR branch submission from contributor npubs.
|
||||||
|
7. Add a one-click fork flow that publishes a contributor-owned fork
|
||||||
|
announcement referencing canonical Archipelago.
|
||||||
|
8. Keep maintainer merge/status publication manual.
|
||||||
|
|
||||||
|
## Later
|
||||||
|
|
||||||
|
- Native PR review UI with file diffs and inline comments.
|
||||||
|
- CI status events signed by the build identity.
|
||||||
|
- FIPS-first source sync between trusted Archipelago nodes.
|
||||||
|
- Private prerelease repositories using NIP-42 allow lists and/or protected
|
||||||
|
events if the ecosystem support is mature enough.
|
||||||
|
- Multi-maintainer policy with threshold signatures or explicit maintainer-list
|
||||||
|
rotation events.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
- Which maintainer npub should become canonical for `archy`?
|
||||||
|
- Should contributor identities be node-default or app-specific by default?
|
||||||
|
- Which GRASP implementation should be deployed first: `ngit-grasp` or another
|
||||||
|
NIP-34/GRASP-compatible relay?
|
||||||
|
- Should the source app include a full web Git UI in v1, or launch Gitea/ngit
|
||||||
|
browser links for review while keeping signing/submission native?
|
||||||
|
- What exact license and contribution certificate should contributors accept
|
||||||
|
before submitting PR events?
|
||||||
@ -2834,7 +2834,7 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
Environment=ANTHROPIC_API_KEY=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
|
Environment=ANTHROPIC_API_KEY=
|
||||||
ExecStart=/usr/bin/python3 /opt/archipelago/claude-api-proxy.py
|
ExecStart=/usr/bin/python3 /opt/archipelago/claude-api-proxy.py
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|||||||
39
neode-ui/THIRD-PARTY-LICENSES.md
Normal file
39
neode-ui/THIRD-PARTY-LICENSES.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Third-Party Licenses — neode-ui (web frontend)
|
||||||
|
|
||||||
|
Runtime dependencies bundled into the distributed web UI. Verified 2026-07-23.
|
||||||
|
Dev-only tooling (Vite, Playwright, TypeScript, etc.) is not distributed and
|
||||||
|
is not listed here. Note: the production bundler strips license header
|
||||||
|
comments, so this file (and the fonts' adjacent license files) constitute the
|
||||||
|
attribution shipped with the bundle; a build-time license-aggregation step is
|
||||||
|
planned (see docs/LICENSE-COMPLIANCE-AUDIT.md).
|
||||||
|
|
||||||
|
| Package | Version | License |
|
||||||
|
|---|---|---|
|
||||||
|
| vue | 3.5.x | MIT |
|
||||||
|
| vue-router | 4.6.x | MIT |
|
||||||
|
| vue-i18n | 11.3.x | MIT |
|
||||||
|
| pinia | 3.0.x | MIT |
|
||||||
|
| d3 | 7.9.x | ISC |
|
||||||
|
| leaflet | 1.9.x | BSD-2-Clause |
|
||||||
|
| @vue-leaflet/vue-leaflet | 0.10.x | MIT |
|
||||||
|
| dompurify | 3.4.x | MPL-2.0 OR Apache-2.0 (used under Apache-2.0) |
|
||||||
|
| buffer | 6.0.x | MIT |
|
||||||
|
| fast-json-patch | 3.1.x | MIT |
|
||||||
|
| fuse.js | 7.1.x | Apache-2.0 |
|
||||||
|
| qrcode | 1.5.x | MIT |
|
||||||
|
| qr-scanner | 1.4.x | MIT |
|
||||||
|
| qrloop | 1.4.x | MIT |
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
| Font | License | License file |
|
||||||
|
|---|---|---|
|
||||||
|
| Montserrat | SIL OFL 1.1 | public/assets/fonts/Montserrat/OFL.txt |
|
||||||
|
| Open Sans | Apache-2.0 | public/assets/fonts/Open_Sans/LICENSE.txt |
|
||||||
|
|
||||||
|
## Vendored
|
||||||
|
|
||||||
|
- `public/assets/icon/` — see ATTRIBUTION.md in that directory
|
||||||
|
(game-icons.net CC BY 3.0; pixelarticons MIT).
|
||||||
|
- `public/assets/img/mesh-devices/` — Meshtastic project artwork, GPL-3.0;
|
||||||
|
see ATTRIBUTION.md in that directory.
|
||||||
11
neode-ui/public/assets/icon/ATTRIBUTION.md
Normal file
11
neode-ui/public/assets/icon/ATTRIBUTION.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Icon Attribution
|
||||||
|
|
||||||
|
- `barbarian.svg`, `batteries.svg` — from **game-icons.net**
|
||||||
|
(https://game-icons.net), by Lorc, Delapouite & contributors,
|
||||||
|
licensed under CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/).
|
||||||
|
- Pixel-style icons (`save.svg`, `paint-bucket.svg`, `fill-half.svg`,
|
||||||
|
`cloud-moon.svg`, `debug-off.svg`, `cloud-done.svg`) — from
|
||||||
|
**pixelarticons** by Gerrit Halfmann (https://github.com/halfmage/pixelarticons),
|
||||||
|
MIT License.
|
||||||
|
- All other icons are original Archipelago artwork (MIT, see repository
|
||||||
|
LICENSE).
|
||||||
13
neode-ui/public/assets/img/mesh-devices/ATTRIBUTION.md
Normal file
13
neode-ui/public/assets/img/mesh-devices/ATTRIBUTION.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Device Artwork Attribution
|
||||||
|
|
||||||
|
The device illustrations in this directory are from the
|
||||||
|
**Meshtastic® project** — https://meshtastic.org
|
||||||
|
(https://github.com/meshtastic), © Meshtastic contributors,
|
||||||
|
licensed under GPL-3.0.
|
||||||
|
|
||||||
|
Meshtastic® is a registered trademark of Meshtastic LLC, used here solely to
|
||||||
|
identify compatible hardware. No endorsement by the Meshtastic project is
|
||||||
|
implied.
|
||||||
|
|
||||||
|
Any modifications to these images made for Archipelago are likewise available
|
||||||
|
under GPL-3.0 as part of this public repository.
|
||||||
@ -113,7 +113,7 @@
|
|||||||
<div v-if="statusMessage" class="mb-3 p-3 rounded-lg text-xs" :class="statusIsError ? 'bg-red-400/10 text-red-300' : 'bg-green-400/10 text-green-300'">{{ statusMessage }}</div>
|
<div v-if="statusMessage" class="mb-3 p-3 rounded-lg text-xs" :class="statusIsError ? 'bg-red-400/10 text-red-300' : 'bg-green-400/10 text-green-300'">{{ statusMessage }}</div>
|
||||||
|
|
||||||
<div v-if="status.key_present && !status.service_active" class="flex gap-2 mt-auto pt-3 shrink-0">
|
<div v-if="status.key_present && !status.service_active" class="flex gap-2 mt-auto pt-3 shrink-0">
|
||||||
<button class="flex-1 min-h-[44px] px-4 py-2 glass-button rounded-lg text-sm font-medium transition-colors" :disabled="installing" @click="installAndActivate">{{ installing ? 'Installing…' : 'Activate' }}</button>
|
<button class="flex-1 min-h-[44px] px-4 py-2 glass-button rounded-lg text-sm font-medium transition-colors" :disabled="installing" @click="installAndActivate">{{ installing ? 'Starting…' : 'Start' }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -211,10 +211,10 @@ async function installAndActivate() {
|
|||||||
installing.value = true
|
installing.value = true
|
||||||
try {
|
try {
|
||||||
status.value = await rpcClient.call<FipsStatus>({ method: 'fips.install' })
|
status.value = await rpcClient.call<FipsStatus>({ method: 'fips.install' })
|
||||||
flash('FIPS installed and activated')
|
flash('FIPS started')
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const msg = e instanceof Error ? e.message : String(e)
|
const msg = e instanceof Error ? e.message : String(e)
|
||||||
flash(`Install failed: ${msg}`, true)
|
flash(`Start failed: ${msg}`, true)
|
||||||
} finally {
|
} finally {
|
||||||
installing.value = false
|
installing.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -362,6 +362,20 @@ init()
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||||
|
<!-- v1.7.117-alpha -->
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.117-alpha</span>
|
||||||
|
<span class="text-xs text-white/40">July 27, 2026</span>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||||
|
<p>FIPS startup is more reliable on nodes that have the packaged fips.service instead of Archipelago's archipelago-fips.service. Startup self-heal, onboarding, dashboard Start, and reconnect now use the systemd unit the node actually has, so FIPS no longer looks like it needs to be installed when it only needs to be started.</p>
|
||||||
|
<p>App screens over the FIPS mesh now bind their relay only to the node's FIPS address instead of reserving the same host ports Podman needs. This keeps apps such as FileBrowser and Botfights from restart-looping because the backend was already holding their published ports.</p>
|
||||||
|
<p>Companion WebView safe-area handling now also moves fixed and sticky top bars below the phone status bar, including headers mounted after page load by single-page apps.</p>
|
||||||
|
<p>Public-source preparation now includes a Nostr Git hosting plan using ngit, NIP-34, and GRASP: anyone can clone, fork, review, and propose changes from their Archipelago node, while canonical merge authority stays with a small signed maintainer set in the style of Bitcoin Core.</p>
|
||||||
|
<p>Node OS release notes for v1.7.117 are still open; add any installer, service, kernel, firewall, or package changes here before cutting the release.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- v1.7.116-alpha -->
|
<!-- v1.7.116-alpha -->
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2 mb-3">
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
|||||||
@ -25,7 +25,7 @@ PATTERNS=(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Allowed files (config templates, docs, test fixtures)
|
# Allowed files (config templates, docs, test fixtures)
|
||||||
ALLOW_PATTERNS="test|mock|example|template|CLAUDE.md|deploy-config|\.md$|node_modules|dist|target|default\)|grep.*rpc|audit-secrets"
|
ALLOW_PATTERNS="test|e2e|mock|demo|example|Example|template|CLAUDE.md|deploy-config|\.md$|node_modules|dist|target|default\)|grep.*rpc|audit-secrets|startsWith|should start with"
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
log "=== Secrets Audit ==="
|
log "=== Secrets Audit ==="
|
||||||
@ -34,7 +34,7 @@ main() {
|
|||||||
# 1. Check for .env files in version control
|
# 1. Check for .env files in version control
|
||||||
log "1. Checking for .env files in git..."
|
log "1. Checking for .env files in git..."
|
||||||
local env_files
|
local env_files
|
||||||
env_files=$(cd "$REPO_ROOT" && git ls-files '*.env' '.env*' 2>/dev/null || echo "")
|
env_files=$(cd "$REPO_ROOT" && git ls-files | grep -E '(^|/)\.env($|[.])|(^|/)[^/]*\.env($|[.])' | grep -vE '(^|/)\.env\.example$|(^|/)[^/]*\.env\.example$' || echo "")
|
||||||
if [ -z "$env_files" ]; then
|
if [ -z "$env_files" ]; then
|
||||||
pass "No .env files tracked in git"
|
pass "No .env files tracked in git"
|
||||||
else
|
else
|
||||||
@ -69,7 +69,7 @@ main() {
|
|||||||
if [ -n "$matches" ]; then
|
if [ -n "$matches" ]; then
|
||||||
# Filter out false positives (empty strings, variable declarations, etc.)
|
# Filter out false positives (empty strings, variable declarations, etc.)
|
||||||
local real_matches
|
local real_matches
|
||||||
real_matches=$(echo "$matches" | grep -vE '""|\x27\x27|None|null|undefined|TODO|placeholder|example|Option<' || echo "")
|
real_matches=$(echo "$matches" | grep -vE '""|\x27\x27|None|null|undefined|TODO|placeholder|example|Option<|\$\{[A-Z0-9_]+:-\}|\$[A-Z0-9_]+|TestPassword|password123|entertoexit' || echo "")
|
||||||
if [ -n "$real_matches" ]; then
|
if [ -n "$real_matches" ]; then
|
||||||
echo " WARNING: Pattern '$pattern' found:"
|
echo " WARNING: Pattern '$pattern' found:"
|
||||||
echo "$real_matches" | head -5 | sed 's/^/ /'
|
echo "$real_matches" | head -5 | sed 's/^/ /'
|
||||||
@ -96,7 +96,7 @@ main() {
|
|||||||
# 5. Check for credential files in repo
|
# 5. Check for credential files in repo
|
||||||
log "5. Checking for credential files..."
|
log "5. Checking for credential files..."
|
||||||
local cred_files
|
local cred_files
|
||||||
cred_files=$(cd "$REPO_ROOT" && git ls-files '*.pem' '*.key' '*macaroon*' 2>/dev/null | grep -v '\.rs$' | grep -v '\.ts$' || echo "")
|
cred_files=$(cd "$REPO_ROOT" && git ls-files | grep -Ei '(\.pem$|\.key$|\.p12$|\.pfx$|\.jks$|\.keystore$|id_rsa|id_ed25519|macaroon)' | grep -vE '\.(rs|ts)$' || echo "")
|
||||||
if [ -z "$cred_files" ]; then
|
if [ -z "$cred_files" ]; then
|
||||||
pass "No credential files tracked in git"
|
pass "No credential files tracked in git"
|
||||||
else
|
else
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Run all Archipelago tests: frontend (local) + backend (dev server via SSH).
|
# Run Archipelago tests.
|
||||||
# Exit 0 only if both pass.
|
#
|
||||||
|
# By default this runs frontend tests and local backend Rust tests. Set
|
||||||
|
# ARCHIPELAGO_SSH_HOST and ARCHIPELAGO_SSH_KEY to run backend tests on a Linux
|
||||||
|
# target instead.
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
|
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-}"
|
||||||
SSH_HOST="${ARCHIPELAGO_SSH_HOST:-archipelago@192.168.1.228}"
|
SSH_HOST="${ARCHIPELAGO_SSH_HOST:-}"
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
@ -29,34 +32,29 @@ fi
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# --- Backend Tests (on dev server) ---
|
# --- Backend Tests ---
|
||||||
echo "--- Backend Tests (dev server) ---"
|
if [[ -n "$SSH_HOST" && -n "$SSH_KEY" ]]; then
|
||||||
|
echo "--- Backend Tests (Linux target: $SSH_HOST) ---"
|
||||||
|
echo "Syncing source to target..."
|
||||||
|
rsync -az --exclude 'target' --exclude 'node_modules' --exclude '.git' \
|
||||||
|
-e "ssh -i $SSH_KEY" \
|
||||||
|
"$PROJECT_DIR/core/" "$SSH_HOST:~/archy/core/" 2>&1
|
||||||
|
|
||||||
# Sync source to server
|
if ssh -i "$SSH_KEY" "$SSH_HOST" \
|
||||||
echo "Syncing source to dev server..."
|
"source ~/.cargo/env && cd ~/archy/core && cargo test --all-features 2>&1"; then
|
||||||
rsync -az --exclude 'target' --exclude 'node_modules' --exclude '.git' \
|
echo "✅ Backend tests PASSED"
|
||||||
-e "ssh -i $SSH_KEY" \
|
BACKEND_OK=1
|
||||||
"$PROJECT_DIR/core/" "$SSH_HOST:~/archy/core/" 2>&1
|
else
|
||||||
|
echo "❌ Backend tests FAILED"
|
||||||
# Run tests on server
|
fi
|
||||||
if ssh -i "$SSH_KEY" "$SSH_HOST" \
|
|
||||||
"source ~/.cargo/env && cd ~/archy/core && cargo test -p archipelago 2>&1"; then
|
|
||||||
echo "✅ Backend unit tests PASSED"
|
|
||||||
BACKEND_OK=1
|
|
||||||
else
|
else
|
||||||
echo "❌ Backend unit tests FAILED"
|
echo "--- Backend Tests (local) ---"
|
||||||
fi
|
if (cd "$PROJECT_DIR/core" && cargo test --all-features 2>&1); then
|
||||||
|
echo "✅ Backend tests PASSED"
|
||||||
echo ""
|
BACKEND_OK=1
|
||||||
|
else
|
||||||
# --- Integration Tests ---
|
echo "❌ Backend tests FAILED"
|
||||||
echo "--- Integration Tests (dev server) ---"
|
fi
|
||||||
if ssh -i "$SSH_KEY" "$SSH_HOST" \
|
|
||||||
"source ~/.cargo/env && cd ~/archy/core && cargo test --test rpc_integration 2>&1"; then
|
|
||||||
echo "✅ Integration tests PASSED"
|
|
||||||
else
|
|
||||||
echo "❌ Integration tests FAILED"
|
|
||||||
BACKEND_OK=0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@ -24,8 +24,9 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|||||||
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
|
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
|
||||||
SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY"
|
SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY"
|
||||||
|
|
||||||
# Anthropic API key — used by all servers for AIUI Claude chat
|
# Anthropic API key used by the AIUI Claude chat proxy. Keep this in the
|
||||||
ANTHROPIC_API_KEY="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"
|
# caller's environment or scripts/deploy-config.sh; never commit live keys.
|
||||||
|
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
|
||||||
|
|
||||||
TARGET_HOST="$1"
|
TARGET_HOST="$1"
|
||||||
if [ -z "$TARGET_HOST" ]; then
|
if [ -z "$TARGET_HOST" ]; then
|
||||||
@ -34,6 +35,12 @@ if [ -z "$TARGET_HOST" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "$ANTHROPIC_API_KEY" ]; then
|
||||||
|
echo "ERROR: ANTHROPIC_API_KEY must be set in the environment."
|
||||||
|
echo "Example: ANTHROPIC_API_KEY=<key> $0 $TARGET_HOST"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist"
|
AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist"
|
||||||
if [ ! -f "$AIUI_DIST/index.html" ]; then
|
if [ ! -f "$AIUI_DIST/index.html" ]; then
|
||||||
echo "ERROR: AIUI build not found at $AIUI_DIST"
|
echo "ERROR: AIUI build not found at $AIUI_DIST"
|
||||||
|
|||||||
@ -1,25 +1,26 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# validate-app-manifest.sh — Validate a community-submitted app manifest
|
# validate-app-manifest.sh - validate an Archipelago app manifest.
|
||||||
#
|
#
|
||||||
# Usage: ./scripts/validate-app-manifest.sh <manifest.yml>
|
# Usage:
|
||||||
|
# ./scripts/validate-app-manifest.sh [--repo-audit] apps/my-app/manifest.yml
|
||||||
#
|
#
|
||||||
# Checks:
|
# This intentionally mirrors the public app contract documented in
|
||||||
# 1. Valid YAML syntax
|
# docs/app-manifest-spec.md: manifests have a top-level `app:` block and are
|
||||||
# 2. Required fields present (id, title, version, image, description)
|
# ultimately validated by the Rust parser in core/container/src/manifest.rs.
|
||||||
# 3. Image from trusted registry (docker.io, ghcr.io, quay.io)
|
# This script is the contributor-friendly preflight; the Rust parser remains
|
||||||
# 4. No :latest tag (must pin specific version)
|
# canonical.
|
||||||
# 5. Resource limits specified (memory, cpu)
|
|
||||||
# 6. Security: no privileged mode, no host networking
|
|
||||||
# 7. No hardcoded secrets/passwords in environment
|
|
||||||
# 8. Port conflicts with existing apps
|
|
||||||
#
|
|
||||||
# Exit 0 = valid, Exit 1 = issues found
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
REPO_AUDIT=0
|
||||||
echo "Usage: $0 <manifest.yml>"
|
if [[ "${1:-}" == "--repo-audit" ]]; then
|
||||||
|
REPO_AUDIT=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $# -ne 1 ]]; then
|
||||||
|
echo "Usage: $0 [--repo-audit] <manifest.yml>"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -30,138 +31,235 @@ WARN=0
|
|||||||
|
|
||||||
check() {
|
check() {
|
||||||
local desc="$1" result="$2"
|
local desc="$1" result="$2"
|
||||||
if [[ "$result" == "pass" ]]; then
|
case "$result" in
|
||||||
PASS=$((PASS + 1))
|
pass)
|
||||||
echo " PASS: $desc"
|
PASS=$((PASS + 1))
|
||||||
elif [[ "$result" == "warn" ]]; then
|
echo " PASS: $desc"
|
||||||
WARN=$((WARN + 1))
|
;;
|
||||||
echo " WARN: $desc"
|
warn)
|
||||||
else
|
WARN=$((WARN + 1))
|
||||||
FAIL=$((FAIL + 1))
|
echo " WARN: $desc"
|
||||||
echo " FAIL: $desc"
|
;;
|
||||||
fi
|
*)
|
||||||
|
FAIL=$((FAIL + 1))
|
||||||
|
echo " FAIL: $desc"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_eval() {
|
||||||
|
ruby -ryaml -e '
|
||||||
|
path, expr = ARGV
|
||||||
|
data = YAML.load_file(path)
|
||||||
|
app = data.is_a?(Hash) ? data["app"] : nil
|
||||||
|
abort "missing top-level app block" unless app.is_a?(Hash)
|
||||||
|
value = eval(expr)
|
||||||
|
case value
|
||||||
|
when Array
|
||||||
|
puts value.join("\n")
|
||||||
|
when Hash
|
||||||
|
puts value.to_a.map { |k, v| "#{k}=#{v}" }.join("\n")
|
||||||
|
when NilClass
|
||||||
|
puts ""
|
||||||
|
else
|
||||||
|
puts value
|
||||||
|
end
|
||||||
|
' "$MANIFEST" "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Validating: $MANIFEST"
|
echo "Validating: $MANIFEST"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 1. File exists and is readable
|
|
||||||
if [[ ! -f "$MANIFEST" ]]; then
|
if [[ ! -f "$MANIFEST" ]]; then
|
||||||
echo " FAIL: File not found: $MANIFEST"
|
echo " FAIL: File not found: $MANIFEST"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
check "File exists" "pass"
|
check "File exists" "pass"
|
||||||
|
|
||||||
# 2. Valid YAML
|
if ! ruby -ryaml -e 'data = YAML.load_file(ARGV[0]); exit(data.is_a?(Hash) && data["app"].is_a?(Hash) ? 0 : 1)' "$MANIFEST" 2>/dev/null; then
|
||||||
if ! python3 -c "import yaml; yaml.safe_load(open('$MANIFEST'))" 2>/dev/null; then
|
check "Valid YAML with top-level app block" "fail"
|
||||||
check "Valid YAML syntax" "fail"
|
echo ""
|
||||||
echo " Cannot continue with invalid YAML"
|
echo "Results: $PASS passed, $FAIL failed, $WARN warnings"
|
||||||
|
echo "STATUS: REJECTED - fix failures before resubmitting"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
check "Valid YAML syntax" "pass"
|
check "Valid YAML with top-level app block" "pass"
|
||||||
|
|
||||||
# 3. Required fields
|
APP_ID="$(yaml_eval 'app["id"]')"
|
||||||
CONTENT=$(python3 -c "
|
APP_NAME="$(yaml_eval 'app["name"]')"
|
||||||
import yaml, json
|
APP_VERSION="$(yaml_eval 'app["version"]')"
|
||||||
with open('$MANIFEST') as f:
|
APP_DESCRIPTION="$(yaml_eval 'app["description"]')"
|
||||||
d = yaml.safe_load(f)
|
APP_INTERNAL="$(yaml_eval 'app["internal"]')"
|
||||||
print(json.dumps(d))
|
IMAGE="$(yaml_eval '(app["container"] || {})["image"]')"
|
||||||
" 2>/dev/null)
|
BUILD_CONTEXT="$(yaml_eval '(((app["container"] || {})["build"] || {})["context"])')"
|
||||||
|
BUILD_TAG="$(yaml_eval '(((app["container"] || {})["build"] || {})["tag"])')"
|
||||||
|
|
||||||
for field in id title version description; do
|
if [[ "$APP_ID" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||||
val=$(echo "$CONTENT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('$field',''))" 2>/dev/null)
|
check "app.id is lowercase kebab-case ($APP_ID)" "pass"
|
||||||
if [[ -n "$val" && "$val" != "None" ]]; then
|
|
||||||
check "Required field '$field' present" "pass"
|
|
||||||
else
|
|
||||||
check "Required field '$field' present" "fail"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 4. Image reference
|
|
||||||
IMAGE=$(echo "$CONTENT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('image','') or d.get('docker_image','') or '')" 2>/dev/null)
|
|
||||||
if [[ -z "$IMAGE" || "$IMAGE" == "None" ]]; then
|
|
||||||
check "Container image specified" "fail"
|
|
||||||
else
|
else
|
||||||
check "Container image specified" "pass"
|
check "app.id is lowercase kebab-case" "fail"
|
||||||
|
fi
|
||||||
|
|
||||||
# Check trusted registry
|
if [[ -n "$APP_NAME" ]]; then
|
||||||
|
check "app.name present" "pass"
|
||||||
|
else
|
||||||
|
check "app.name present" "fail"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$APP_VERSION" =~ [0-9] ]]; then
|
||||||
|
check "app.version present and contains a digit" "pass"
|
||||||
|
else
|
||||||
|
check "app.version present and contains a digit" "fail"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$APP_DESCRIPTION" ]]; then
|
||||||
|
check "app.description present" "pass"
|
||||||
|
else
|
||||||
|
check "app.description present" "warn"
|
||||||
|
fi
|
||||||
|
|
||||||
|
HAS_IMAGE=0
|
||||||
|
HAS_BUILD=0
|
||||||
|
[[ -n "$IMAGE" ]] && HAS_IMAGE=1
|
||||||
|
[[ -n "$BUILD_CONTEXT" || -n "$BUILD_TAG" ]] && HAS_BUILD=1
|
||||||
|
|
||||||
|
if [[ "$HAS_IMAGE" -eq 1 && "$HAS_BUILD" -eq 0 ]]; then
|
||||||
|
check "container.image specified" "pass"
|
||||||
|
elif [[ "$HAS_IMAGE" -eq 0 && "$HAS_BUILD" -eq 1 ]]; then
|
||||||
|
if [[ -n "$BUILD_CONTEXT" && -n "$BUILD_TAG" ]]; then
|
||||||
|
check "container.build specified with context and tag" "pass"
|
||||||
|
else
|
||||||
|
check "container.build requires context and tag" "fail"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
check "exactly one of container.image or container.build specified" "fail"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$IMAGE" ]]; then
|
||||||
TRUSTED=false
|
TRUSTED=false
|
||||||
for reg in "docker.io" "ghcr.io" "quay.io" "registry.hub.docker.com" "146.59.87.168:3000"; do
|
for reg in "docker.io" "ghcr.io" "quay.io" "registry.hub.docker.com" "146.59.87.168:3000" "localhost/"; do
|
||||||
if echo "$IMAGE" | grep -q "$reg"; then
|
if [[ "$IMAGE" == *"$reg"* ]]; then
|
||||||
TRUSTED=true
|
TRUSTED=true
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
# Also allow short-form Docker Hub images (no registry prefix)
|
if [[ "$TRUSTED" == "true" || "$IMAGE" != */* ]]; then
|
||||||
if ! echo "$IMAGE" | grep -q "/"; then
|
check "image registry is recognized" "pass"
|
||||||
TRUSTED=true # single-name images are Docker Hub official
|
|
||||||
fi
|
|
||||||
if [[ "$TRUSTED" == "true" ]]; then
|
|
||||||
check "Image from trusted registry" "pass"
|
|
||||||
else
|
else
|
||||||
check "Image from trusted registry ($IMAGE)" "warn"
|
check "image registry is not in the reviewed list ($IMAGE)" "warn"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check no :latest
|
if [[ "$IMAGE" == *":latest" ]]; then
|
||||||
if echo "$IMAGE" | grep -q ":latest$"; then
|
if [[ "$APP_INTERNAL" == "true" || "$IMAGE" == localhost/* ]]; then
|
||||||
check "No :latest tag (pin specific version)" "fail"
|
check "internal/local build uses :latest ($IMAGE)" "warn"
|
||||||
elif ! echo "$IMAGE" | grep -q ":"; then
|
elif [[ "$REPO_AUDIT" -eq 1 ]]; then
|
||||||
check "No version tag specified (should pin version)" "warn"
|
check "existing manifest uses :latest and must be pinned before public app submission ($IMAGE)" "warn"
|
||||||
|
else
|
||||||
|
check "image tag is pinned and not :latest ($IMAGE)" "fail"
|
||||||
|
fi
|
||||||
|
elif [[ "$IMAGE" != *:* ]]; then
|
||||||
|
check "image tag is explicit ($IMAGE)" "warn"
|
||||||
else
|
else
|
||||||
check "Version tag pinned" "pass"
|
check "image tag is pinned" "pass"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5. Security checks
|
MEMORY_LIMIT="$(yaml_eval '((app["resources"] || {})["memory_limit"] || (app["resources"] || {})["memory"])')"
|
||||||
PRIVILEGED=$(echo "$CONTENT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('privileged', False))" 2>/dev/null)
|
CPU_LIMIT="$(yaml_eval '((app["resources"] || {})["cpu_limit"] || (app["resources"] || {})["cpu"])')"
|
||||||
if [[ "$PRIVILEGED" == "True" ]]; then
|
[[ -n "$MEMORY_LIMIT" ]] && check "resources.memory_limit specified ($MEMORY_LIMIT)" "pass" || check "resources.memory_limit specified" "warn"
|
||||||
check "No privileged mode" "fail"
|
[[ -n "$CPU_LIMIT" ]] && check "resources.cpu_limit specified ($CPU_LIMIT)" "pass" || check "resources.cpu_limit specified" "warn"
|
||||||
|
|
||||||
|
READONLY_ROOT="$(yaml_eval '((app["security"] || {})["readonly_root"])')"
|
||||||
|
NO_NEW_PRIVS="$(yaml_eval '((app["security"] || {})["no_new_privileges"])')"
|
||||||
|
NETWORK_POLICY="$(yaml_eval '((app["security"] || {})["network_policy"])')"
|
||||||
|
CONTAINER_NETWORK="$(yaml_eval '((app["container"] || {})["network"])')"
|
||||||
|
|
||||||
|
if [[ "$READONLY_ROOT" == "true" || -z "$READONLY_ROOT" ]]; then
|
||||||
|
check "security.readonly_root true (explicit or Rust default)" "pass"
|
||||||
else
|
else
|
||||||
check "No privileged mode" "pass"
|
check "security.readonly_root true or explicitly justified" "warn"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
HOST_NET=$(echo "$CONTENT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('host_network', d.get('network_mode','')))" 2>/dev/null)
|
if [[ "$NO_NEW_PRIVS" == "true" || -z "$NO_NEW_PRIVS" ]]; then
|
||||||
if [[ "$HOST_NET" == "host" ]]; then
|
check "security.no_new_privileges true (explicit or Rust default)" "pass"
|
||||||
check "No host networking" "fail"
|
elif [[ "$REPO_AUDIT" -eq 1 ]]; then
|
||||||
|
check "existing manifest disables security.no_new_privileges and needs review" "warn"
|
||||||
else
|
else
|
||||||
check "No host networking" "pass"
|
check "security.no_new_privileges true" "fail"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 6. Check for hardcoded secrets in env vars
|
if [[ "$NETWORK_POLICY" == "isolated" || "$NETWORK_POLICY" == "bridge" || "$NETWORK_POLICY" == "host" || -z "$NETWORK_POLICY" ]]; then
|
||||||
ENV_VARS=$(echo "$CONTENT" | python3 -c "
|
check "security.network_policy valid" "pass"
|
||||||
import sys,json
|
|
||||||
d=json.load(sys.stdin)
|
|
||||||
env = d.get('environment', d.get('env', {}))
|
|
||||||
if isinstance(env, dict):
|
|
||||||
for k,v in env.items():
|
|
||||||
print(f'{k}={v}')
|
|
||||||
elif isinstance(env, list):
|
|
||||||
for e in env:
|
|
||||||
print(e)
|
|
||||||
" 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
SECRET_PATTERNS="password|secret|api_key|private_key|token"
|
|
||||||
if echo "$ENV_VARS" | grep -iqE "$SECRET_PATTERNS"; then
|
|
||||||
check "No hardcoded secrets in environment" "warn"
|
|
||||||
else
|
else
|
||||||
check "No hardcoded secrets in environment" "pass"
|
check "security.network_policy valid" "fail"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7. Memory limit
|
if [[ "$CONTAINER_NETWORK" == container:* || "$CONTAINER_NETWORK" == ns:* ]]; then
|
||||||
MEM=$(echo "$CONTENT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('memory', d.get('mem_limit', d.get('resources',{}).get('memory',''))))" 2>/dev/null)
|
check "container.network does not share another namespace" "fail"
|
||||||
if [[ -n "$MEM" && "$MEM" != "None" && "$MEM" != "" ]]; then
|
|
||||||
check "Memory limit specified ($MEM)" "pass"
|
|
||||||
else
|
else
|
||||||
check "Memory limit specified" "warn"
|
check "container.network does not share another namespace" "pass"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SECRET_ENV="$(yaml_eval '(app["environment"] || [])')"
|
||||||
|
if echo "$SECRET_ENV" | grep -iqE '^[A-Z0-9_]*(PASSWORD|PASS|SECRET|TOKEN|API_KEY|PRIVATE_KEY)[A-Z0-9_]*=.+$'; then
|
||||||
|
check "no hardcoded secret-like values in app.environment" "warn"
|
||||||
|
else
|
||||||
|
check "no hardcoded secret-like values in app.environment" "pass"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$APP_ID" && -n "$MANIFEST" ]]; then
|
||||||
|
EXPECTED_DIR="$(basename "$(dirname "$MANIFEST")")"
|
||||||
|
if [[ "$EXPECTED_DIR" == "$APP_ID" ]]; then
|
||||||
|
check "app.id matches directory name" "pass"
|
||||||
|
elif [[ "$REPO_AUDIT" -eq 1 ]]; then
|
||||||
|
check "existing manifest app.id differs from directory name ($EXPECTED_DIR)" "warn"
|
||||||
|
else
|
||||||
|
check "app.id matches directory name ($EXPECTED_DIR)" "fail"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
PORT_CHECK="$(ruby -ryaml -e '
|
||||||
|
current = ARGV[0]
|
||||||
|
current_id = File.basename(File.dirname(current))
|
||||||
|
ports = {}
|
||||||
|
Dir.glob("apps/*/manifest.yml").sort.each do |path|
|
||||||
|
data = YAML.load_file(path)
|
||||||
|
app = data.is_a?(Hash) ? data["app"] : nil
|
||||||
|
next unless app.is_a?(Hash)
|
||||||
|
id = app["id"] || File.basename(File.dirname(path))
|
||||||
|
next if id == current_id
|
||||||
|
Array(app["ports"]).each do |p|
|
||||||
|
next unless p.is_a?(Hash)
|
||||||
|
proto = p["protocol"] || "tcp"
|
||||||
|
bind = p["bind"] || ""
|
||||||
|
host = p["host"]
|
||||||
|
ports[[host, proto, bind]] = id if host
|
||||||
|
end
|
||||||
|
end
|
||||||
|
data = YAML.load_file(current)
|
||||||
|
app = data["app"]
|
||||||
|
conflicts = []
|
||||||
|
Array(app["ports"]).each do |p|
|
||||||
|
next unless p.is_a?(Hash)
|
||||||
|
key = [p["host"], p["protocol"] || "tcp", p["bind"] || ""]
|
||||||
|
conflicts << "#{key[2].empty? ? "*" : key[2]}:#{key[0]}/#{key[1]} already used by #{ports[key]}" if ports.key?(key)
|
||||||
|
end
|
||||||
|
puts conflicts.join("\n")
|
||||||
|
' "$MANIFEST")"
|
||||||
|
if [[ -n "$PORT_CHECK" ]]; then
|
||||||
|
while IFS= read -r conflict; do
|
||||||
|
check "port conflict: $conflict" "warn"
|
||||||
|
done <<< "$PORT_CHECK"
|
||||||
|
else
|
||||||
|
check "no duplicate host port bindings" "pass"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Results: $PASS passed, $FAIL failed, $WARN warnings"
|
echo "Results: $PASS passed, $FAIL failed, $WARN warnings"
|
||||||
|
|
||||||
if [[ "$FAIL" -gt 0 ]]; then
|
if [[ "$FAIL" -gt 0 ]]; then
|
||||||
echo "STATUS: REJECTED — fix failures before resubmitting"
|
echo "STATUS: REJECTED - fix failures before resubmitting"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
|
||||||
echo "STATUS: APPROVED (with $WARN warnings)"
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "STATUS: APPROVED (with $WARN warnings)"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user