From e11c46cb7c92eeb5fc10584bd11a24f50a4aa076 Mon Sep 17 00:00:00 2001 From: Taylor Addison Date: Sat, 5 Sep 2026 18:19:08 -0400 Subject: [PATCH 1/2] An app icon, a card that unfurls, and the mark written down The iOS runner had no Assets.xcassets at all, so every screenshot of it showed the default blank silhouette -- an agent app that looks like a prototype in the one image anybody sees of it. Android's adaptive layers landed with the status screen; this is the other half. The icon is rendered from a new full-bleed cut of the mark rather than from mark.svg, because iOS and Android both apply their own corner mask and a source that rounds itself gets rounded twice. The PNG carries no alpha, which iOS rejects outright. Both project specs pick it up: project.llama.yml includes project.yml, so wiring ASSETCATALOG_COMPILER_APPICON_NAME once covers the framework build too. The repository had no social preview, so every share of the link -- portfolio, chat, anywhere with an unfurl -- rendered GitHub's generated text card instead of the banner that already existed. There is no API for uploading one, so the image is committed and the upload is a click in Settings. architecture.svg is the mermaid diagram exported for surfaces that do not render mermaid. It carries its own charcoal ground on purpose: the labels are light, and without one it is invisible on a white page, which is most of the places it would be dropped. Getting a standalone SVG out of a browser also needs XMLSerializer rather than outerHTML -- the HTML serializer leaves the
inside every foreignObject label unclosed, and a .svg file is parsed as XML, so the whole thing becomes a parse error rather than a diagram. docs/brand.md records the two colours, which mark cut is for what, how each asset is generated, and the two traps above, so the next asset matches this one without anybody re-deriving it. Verified: BUILD SUCCEEDED for the simulator with the icon compiled in (AppIcon60x60@2x.png, AppIcon76x76@2x~ipad.png and Assets.car in the bundle, CFBundleIconName set), the committed project still carries 0 xcframework references, architecture.svg parses as XML and renders, and mkdocs --strict is clean. Co-Authored-By: Claude Opus 5 --- docs/brand.md | 90 ++++++++++++++++++ docs/img/architecture.svg | 2 + docs/img/icon-source.svg | 10 ++ docs/img/social-preview.png | Bin 0 -> 85945 bytes mkdocs.yml | 1 + .../FleetRunner.xcodeproj/project.pbxproj | 15 +++ .../AppIcon.appiconset/Contents.json | 14 +++ .../AppIcon.appiconset/icon-1024.png | Bin 0 -> 19094 bytes .../FleetRunner/Assets.xcassets/Contents.json | 6 ++ runner-ios/project.yml | 1 + 10 files changed, 139 insertions(+) create mode 100644 docs/brand.md create mode 100644 docs/img/architecture.svg create mode 100644 docs/img/icon-source.svg create mode 100644 docs/img/social-preview.png create mode 100644 runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/icon-1024.png create mode 100644 runner-ios/FleetRunner/Assets.xcassets/Contents.json diff --git a/docs/brand.md b/docs/brand.md new file mode 100644 index 0000000..82f6888 --- /dev/null +++ b/docs/brand.md @@ -0,0 +1,90 @@ +# Brand + +Two colours, one mark, one type pairing. Written down so the next asset matches +the last one. + +## Colour + +| | Hex | Where | +|---|---|---| +| **Charcoal** | `#1C2025` | Every ground: the app icon tile, the dashboard, the social card, the diagram | +| **Amber** | `#E3A44A` | The mark's strokes, accents, and links on dark | +| **Amber, dark-on-light** | `#B8791F` | Links and accents on a light ground, where `#E3A44A` fails contrast | + +Amber is the only accent. If something needs a second colour, it is either +semantic (a pass, a warning, a failure) or it does not need a second colour. + +## The mark + +A phone outline with a pulse trace through it, and a home-bar tick below. It +reads at 16 px, which is the constraint it was drawn to — the favicon is the +same line at a quarter of the size, not a different drawing. + +| File | What it is | Use for | +|---|---|---| +| `img/mark.svg` | The mark on a rounded charcoal tile | Documents, favicons, anywhere it sits on an unknown ground | +| `img/mark-mono.svg` | Strokes only, `currentColor`, no tile | On a coloured header — it inherits the foreground. This is the docs-site logo | +| `img/icon-source.svg` | Full-bleed square, no rounded corners | The source both app icons are rendered from | +| `collector/dash/public/favicon.svg` | The pulse alone at 16 px | The dashboard tab | + +!!! warning "App icons must not round their own corners" + + iOS and Android both apply their own mask. A source that is already rounded + gets rounded twice and reads as a smaller, oddly inset icon. + `icon-source.svg` is square and full-bleed for exactly this reason, and the + rendered PNG carries **no alpha channel**, which iOS rejects outright. + +## Type + +| Role | Face | Notes | +|---|---|---| +| Display | Bricolage Grotesque | The social card and headings on generated assets | +| Body | IBM Plex Sans | | +| Mono | IBM Plex Mono | Metrics, device ids, hashes, chips | + +The docs site uses Inter and JetBrains Mono, which is what Material ships and +what its layout is tuned for. Generated assets use the pairing above. + +Numbers that line up in a column get `font-variant-numeric: tabular-nums`. A +benchmark table where the digits do not align is harder to read than one with +fewer digits in it. + +## The assets, and how they are made + +Everything is rendered from source rather than drawn by hand, so it can be +regenerated when the mark changes. + +| Asset | Size | Source | +|---|---|---| +| `img/social-preview.png` | 2560×1280 (2× of GitHub's 1280×640) | An HTML page rendered headless | +| `img/architecture.svg` | 1364×450 | The mermaid source in `index.md`, exported and given its own charcoal ground | +| `img/banner.png` | | The README banner | +| `img/first-result.png` | | The Results screen after one synthetic benchmark on a laptop | +| `img/overview.png`, `devices.png`, `jobs.png`, `results.png` | | Dashboard pages, captured with Playwright against a running collector | +| `runner-ios/.../AppIcon.appiconset/icon-1024.png` | 1024×1024, no alpha | `img/icon-source.svg` | +| `runner-android/.../mipmap*/ic_launcher.xml` | vector | Drawn as Android vector drawables from the same geometry | + +**`architecture.svg` carries its own background** because it is meant to be +dropped onto surfaces this repository does not control — a portfolio page, a +blog post, a slide. Its labels are light, so without a ground it would be +invisible on white. The mermaid source in the docs stays a mermaid block, which +the site themes correctly on its own. + +!!! note "The dashboard screenshots were taken with the fleet offline" + + `overview.png` and `devices.png` show six devices offline and a queue whose + oldest job is twenty days old, because the laptop that captured them was on + a different network from the shelf. It is honest and it reads as abandoned. + Retake them from the fleet's own network. `results.png` and + `first-result.png` are unaffected — they show stored history. + +## Voice + +The project's writing has one rule that matters more than any style guide: +**say what is not true yet.** Every workload page ends with what that workload +refuses to do, every README has a "what works and what does not", and the +integration guide says on its first screen that the GitHub Actions path has +never run on a real runner. + +That is not modesty. A number that gets believed and turns out to be wrong +costs more than one that was never reported. diff --git a/docs/img/architecture.svg b/docs/img/architecture.svg new file mode 100644 index 0000000..e6cb0f6 --- /dev/null +++ b/docs/img/architecture.svg @@ -0,0 +1,2 @@ + +

a Mac with devices plugged in

the shelf

long-poll, claim, report

long-poll, claim, report

long-poll, claim, report

claims host jobs

drives from outside

Android runner

iOS runner

machine runner
laptop or desktop

host executor
adb · Maestro · simctl · Playwright

collector
queue · registry · leases
artifacts · results · scheduler

dashboard

diff --git a/docs/img/icon-source.svg b/docs/img/icon-source.svg new file mode 100644 index 0000000..35ad470 --- /dev/null +++ b/docs/img/icon-source.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/docs/img/social-preview.png b/docs/img/social-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..d40a6ad301b1cee70450f90656be4c7e8b320b29 GIT binary patch literal 85945 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 literal 0 HcmV?d00001 diff --git a/mkdocs.yml b/mkdocs.yml index 956f13e..d9f9fb8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -103,6 +103,7 @@ nav: - Networking: deploy/networking.md - The iOS executor: deploy/ios-executor.md - Alerts: deploy/alerts.md + - Brand: brand.md - History: - Overview: history/index.md - Dashboard plan: history/dashboard-plan.md diff --git a/runner-ios/FleetRunner.xcodeproj/project.pbxproj b/runner-ios/FleetRunner.xcodeproj/project.pbxproj index ac103c3..70572aa 100644 --- a/runner-ios/FleetRunner.xcodeproj/project.pbxproj +++ b/runner-ios/FleetRunner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ E8BB49B17F0F3FA770679941 /* MiniZip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 262BD6B87A5A8B607BE14F2B /* MiniZip.swift */; }; F26997129A574EF8076AA67F /* FleetRunnerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C158F9244D20CE6B927532 /* FleetRunnerApp.swift */; }; F2745828AC9D98D4548FBC33 /* ArtifactCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAB0ABC564FF0A636AF37059 /* ArtifactCache.swift */; }; + F4EBB4A4C44824C4BE88B9EC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E9D9AE076A10932032DC657B /* Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -61,6 +62,7 @@ D1902344387986CFE92D4225 /* FleetRunnerUITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = FleetRunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D322211CB368EAB10C9D22A9 /* CoreMLBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreMLBackend.swift; sourceTree = ""; }; D84C3EEBAE6C004B45C56596 /* SyntheticBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyntheticBackend.swift; sourceTree = ""; }; + E9D9AE076A10932032DC657B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; F4C3A0BD78A079DFBA23D246 /* FleetRunner.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = FleetRunner.app; sourceTree = BUILT_PRODUCTS_DIR; }; FAB0ABC564FF0A636AF37059 /* ArtifactCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtifactCache.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -70,6 +72,7 @@ isa = PBXGroup; children = ( FAB0ABC564FF0A636AF37059 /* ArtifactCache.swift */, + E9D9AE076A10932032DC657B /* Assets.xcassets */, C7DFBDD257E5AD4960202BB7 /* BenchSession.swift */, 31632F0B6302F50DC2BD764E /* CollectorClient.swift */, D322211CB368EAB10C9D22A9 /* CoreMLBackend.swift */, @@ -127,6 +130,7 @@ buildConfigurationList = F3286BB877D4AA75311CE685 /* Build configuration list for PBXNativeTarget "FleetRunner" */; buildPhases = ( A5D4950877F41D019B81DCFE /* Sources */, + 139C8978B9F9E5329A615B5E /* Resources */, ); buildRules = ( ); @@ -191,6 +195,17 @@ }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + 139C8978B9F9E5329A615B5E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F4EBB4A4C44824C4BE88B9EC /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 33591D8880D86DC8B8E6526C /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/Contents.json b/runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..27a4f38 --- /dev/null +++ b/runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "icon-1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/runner-ios/FleetRunner/Assets.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..61fa86d649358ccd96f3b7403918b76680ca5711 GIT binary patch literal 19094 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 z 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 Date: Sat, 5 Sep 2026 18:21:11 -0400 Subject: [PATCH 2/2] A security policy that says what is not a finding, and how to contribute The community profile was at 42%: no CONTRIBUTING, no SECURITY, no code of conduct, no templates. For most projects that is a formality. For one whose front page says "there is no authentication, by design" it is the specific gap that earns a drive-by "critical vulnerability" issue, and answering that issue costs more than writing the policy did. So SECURITY.md leads with the posture rather than burying it: the network is the access control, FLEET_BIND decides which network, and the dashboard token is a speed bump against a stray browser tab rather than an access control -- all of which the README already said, now said somewhere a reporter looks first. Then it names what a real finding would look like, which is the half that keeps the useful reports coming: the shell workload's allowlist, artifact path handling, the web-* workloads fetching arbitrary URLs by design, credentials reaching a log or an uploaded artifact, and FLEET_BIND not binding where it says. CONTRIBUTING.md is the suites, and the things that have cost an evening each: one xcodebuild per simulator, xcodegen by full path in anything non-interactive, do not commit a project regenerated with the framework present, -Pfleet.skipNative is how you run the Android tests with no NDK, and a metric name outside result.schema.json is stored and unqueryable. It ends on the rule the codebase actually runs on -- say what is not true yet -- because that is the review comment a contributor would otherwise get after the fact. The device report template is the point of the whole exercise. The project exists to produce comparable numbers across hardware nobody has a lab full of, and every phone that is not on this shelf is data this repository does not have, including the ones that refused to work. The code of conduct is Contributor Covenant 2.1 unmodified, with its contact placeholder pointed at the maintainer's GitHub rather than an email address, since publishing one in a public file is a decision the owner should make rather than one I should make for him. Co-Authored-By: Claude Opus 5 --- .github/ISSUE_TEMPLATE/bug.yml | 51 ++++++++ .github/ISSUE_TEMPLATE/config.yml | 11 ++ .github/ISSUE_TEMPLATE/device-report.yml | 76 ++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 23 ++++ CODE_OF_CONDUCT.md | 86 +++++++++++++ CONTRIBUTING.md | 147 +++++++++++++++++++++++ README.md | 17 ++- SECURITY.md | 96 +++++++++++++++ 8 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/device-report.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..587f9a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,51 @@ +name: Bug +description: Something behaves differently from what the docs say. +labels: ["bug"] +body: + - type: dropdown + id: component + attributes: + label: Component + options: + - collector + - runner-android + - runner-ios + - runner-machine + - host executor + - dashboard + - docs + validations: + required: true + + - type: textarea + id: expected + attributes: + label: What the docs say, and what happened + description: > + A link to the page or the README line, if there is one. If the + documentation is what is wrong, that is a bug too and it is the easiest + kind to fix. + validations: + required: true + + - type: textarea + id: repro + attributes: + label: How to reproduce + description: > + The commands, and the job spec if one is involved. `npm test` in + `collector/` starts its own throwaway collector, so a repro that runs + there is worth more than one that needs your fleet. + validations: + required: true + + - type: textarea + id: env + attributes: + label: Versions + placeholder: | + fleet-runner: v0.2.0 (or a commit sha) + node: v22.11.0 + os: macOS 26.1 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..7c47d62 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: true +contact_links: + - name: Security report + url: https://github.com/addisdev/fleet-runner/security/advisories/new + about: > + Privately, via GitHub's advisory form. Read SECURITY.md first — the + collector has no authentication by design, and that on its own is not a + finding. + - name: Question, or show your shelf + url: https://github.com/addisdev/fleet-runner/discussions + about: What hardware you are running this on, and anything that is not a bug. diff --git a/.github/ISSUE_TEMPLATE/device-report.yml b/.github/ISSUE_TEMPLATE/device-report.yml new file mode 100644 index 0000000..515eee5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/device-report.yml @@ -0,0 +1,76 @@ +name: Device report +description: What your hardware measured, refused, or broke on. The most useful thing you can send. +title: "[device] " +labels: ["device-report"] +body: + - type: markdown + attributes: + value: | + The whole point of this project is comparable numbers across hardware + nobody has a lab full of. Every phone that is not on this shelf is data + this repository does not have — including the ones that refused to work. + + A report where something failed is as useful as one where it worked. + + - type: input + id: device + attributes: + label: Device + description: Model and SoC, as the runner reports them if you have it. + placeholder: "SM-X930 (Dimensity 9400) / iPhone 16 simulator / ThinkPad X1, i7-1260P" + validations: + required: true + + - type: input + id: os + attributes: + label: OS and RAM + placeholder: "android-15, 12288 MB" + validations: + required: true + + - type: dropdown + id: runner + attributes: + label: Which runner + options: + - runner-android + - runner-ios + - runner-machine + - host executor + validations: + required: true + + - type: input + id: backend + attributes: + label: Workload and backend + placeholder: "benchmark / synthetic, or vision-eval / litert" + validations: + required: true + + - type: textarea + id: spec + attributes: + label: The job spec + description: The JSON you enqueued. Redact hostnames and hashes if you like. + render: json + + - type: textarea + id: result + attributes: + label: The result row + description: > + From `GET /api/results?job=`, or the error if it failed. The + `metrics` object is the part that matters. + render: json + + - type: textarea + id: notes + attributes: + label: Anything surprising + description: > + Numbers that look wrong, a capability that was declared but bounced, a + device left in a state the journals did not record. Especially if a + second device disagreed with this one — that is how the all-zero logits + tensor was caught. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..be07f6f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ + + +## What and why + + + +## Verified + + + +- [ ] Tests run for what I touched, and named above +- [ ] Docs updated in this change (the site builds `--strict`, so a broken link fails CI) +- [ ] `CHANGELOG.md` entry under `## [Unreleased]`, if this is user-visible + +## What is still not true + + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..4c6b5be --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,86 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [@addisdev on GitHub](https://github.com/addisdev), by direct message or by +opening a private report on this repository. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..70ba3d6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,147 @@ +# Contributing + +This is a personal project that was made public because the write-up was worth +sharing. Contributions are welcome and there is no obligation for anyone to +send any. + +The most useful thing you can send is **a device report**: what your hardware +measured, what it refused, and what broke. The whole point of the project is +comparable numbers across hardware nobody has a lab full of, and every phone +that is not on this shelf is data this repository does not have. + +## Running the suites + +Four components, four suites. Only run the one you touched. + +=== "collector" + + ```bash + cd collector + npm install + npm run dash:install # once, for the dashboard build step + npm test + ``` + + `npm test` typechecks, builds the dashboard, checks metric names against + the schema, validates the example job specs, then **starts its own + collector on a kernel-assigned port with a temporary database** and runs + the smoke suite against it. It never touches a real fleet's history, which + is why it can be wired to `npm test` at all. + + It takes about four minutes. + +=== "runner-android" + + ```bash + cd runner-android + ./gradlew :app:testDebugUnitTest -Pfleet.skipNative + ``` + + **`-Pfleet.skipNative` is what lets you run this with no NDK.** The arm64 + llama.cpp build takes about fifteen minutes and needs a pinned NDK, and the + JVM tests never call into it. CI uses the same flag. + + For the native build you need the submodule and NDK 27.2: + + ```bash + git submodule update --init --recursive + ./gradlew :app:assembleDebug + ``` + +=== "runner-ios" + + ```bash + cd runner-ios + brew install xcodegen + ./generate.sh + xcodebuild build -project FleetRunner.xcodeproj -scheme FleetRunner \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath build CODE_SIGNING_ALLOWED=NO + ``` + +=== "runner-machine" + + ```bash + cd runner-machine + npm install && npm test + ``` + + 122 tests, about a second. This is the easiest component to contribute to + and the reference implementation of the protocol. + +## Things this project learned the hard way + +Each of these cost somebody an evening. + +**Run one `xcodebuild` per simulator.** Two concurrent test sessions against +the same simulator send each other `SIGTERM` and wedge it. A "crash" with no +`.ips` file is almost always a collision, not a bug in the app. + +**Call `xcodegen` by its full path in anything non-interactive.** Homebrew's +`bin` is not on a non-interactive `PATH`, so a bare `xcodegen` over SSH or under +launchd fails in a way that looks like the project generated fine and your new +files simply did not compile. `generate.sh` already handles this. + +**Regenerate the Xcode project after syncing files to another machine.** An +`rsync` that carries `*.xcodeproj` across overwrites a project generated for +that machine. Exclude it and run `./generate.sh` on the far end. + +**The committed `FleetRunner.xcodeproj` is deliberately the one without the +llama.cpp framework.** Xcode treats a declared-but-missing XCFramework as a hard +error rather than something to skip, so a spec naming it unconditionally cannot +be built from a fresh clone. If you regenerate with the framework present, the +project will show as modified — do not commit that. + +**A metric name that is not in `result.schema.json` is stored and unqueryable.** +Add it to the schema in the same change that emits it. This has already cost +one write-up its reproducibility: an eval's accuracy rode in `decode_tok_s` +because vision had no field of its own, and no query can reproduce those numbers +today. `npm test` fails if the schema and its mirror disagree. + +**Declare a capability only when the machine can honour it.** A capability +claimed but not implemented is a job the queue hands over and the agent bounces, +which from the dashboard looks exactly like a broken workload. + +## Adding a workload + +You do not need a collector release. The collector accepts any workload a +registered agent declares in its capabilities. See [Add a +workload](https://addisdev.github.io/fleet-runner/integration/add-a-workload/) +and [Writing a runner](https://addisdev.github.io/fleet-runner/writing-a-runner/). + +## The one thing to get right + +**Say what is not true yet.** + +Every workload page ends with what that workload refuses to do. Every README has +a "what works, and what does not". The integration guide says on its first +screen that the GitHub Actions path has never run on a real runner. + +When you cannot measure the thing asked for, fail with a message naming what is +missing. A wrong number recorded as a result is worse than a failure, because a +failure gets investigated and a number gets believed. The iOS Simulator's GPU +returning an all-zero logits tensor — silently, with no error — is the reason +this is the first rule rather than a nice sentiment. + +## Pull requests + +- Branch from `develop`. `main` is the released trunk. +- Run the suite for what you touched, and say in the description what you ran. +- Update the docs in the same change. The site builds with `--strict`, so a + broken link fails CI. +- Add a `CHANGELOG.md` entry under `## [Unreleased]` for anything user-visible. + +`ci-ok` is the only required check. It always reports, and it passes when every +component suite is green **or skipped** — a change to one runner does not build +the others. + +## Dependencies + +**Dependabot is deliberately limited to security alerts and security fixes.** +There is no `dependabot.yml`, which is what keeps version-bump pull requests +from burying the ones that matter. If you want to upgrade something, do it in a +change that says why. + +## Code of conduct + +[Contributor Covenant 2.1](CODE_OF_CONDUCT.md). diff --git a/README.md b/README.md index 70ee8b9..6583b8b 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,22 @@ model and dataset: **[the eval](collector/evals/greenfolio-plant-id.md)**. [The architecture and build plan](https://addisdev.github.io/fleet-runner/history/plan.html) written before any of this existed, kept as-is. Every phase in it was built. +## Contributing + +The most useful thing you can send is **a device report** — what your hardware +measured, what it refused, and what broke. The point of the project is +comparable numbers across hardware nobody has a lab full of, and every phone +that is not on this shelf is data this repository does not have. + +[`CONTRIBUTING.md`](CONTRIBUTING.md) has how to run each component's suite and +the handful of things this project learned the hard way. Behaviour is covered by +the [Contributor Covenant](CODE_OF_CONDUCT.md). + +**There is no authentication, by design** — the collector is built for a home +LAN or a tailnet. [`SECURITY.md`](SECURITY.md) says what that does and does not +cover before you report it. + ## License -MIT — see [LICENSE](LICENSE). Each repository carries its own third-party +MIT — see [LICENSE](LICENSE). Each component carries its own third-party notices for what it links. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..365fcf4 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,96 @@ +# Security policy + +## Read this before reporting + +**Fleet Runner has no authentication, by design.** The collector is built for a +home LAN or a tailnet. Anyone who can reach it can enqueue a job, and a job can +install software on a device, drive a browser, or run a UI suite. + +That is the stated posture, not an oversight, and **"there is no authentication" +is not a vulnerability report.** The network is the access control: +`FLEET_BIND` decides which network, and setting it to loopback plus a tailnet +address is the configuration the documentation recommends. +`FLEET_DASH_TOKEN` guards the dashboard's mutations and is explicitly described +as a speed bump against a stray browser tab, not an access control — `POST /jobs` +stays open so `curl` and CI keep working. + +If you want to put this on the public internet, the honest starting point is +that every endpoint would need re-thinking, not that a token would need adding. + +## What is in scope + +Given that posture, these are the things a report can meaningfully be about. + +**The `shell` workload's trust boundary.** `shell` runs a script named by a job +spec, and `POST /jobs` is unauthenticated, so the machine agent refuses to take +the collector's word for anything: the owner pins a sha256 by hand in a local +allowlist file, the capability is declared **only** when that file exists and is +non-empty, and the hash is checked **before** the artifact is fetched. A way to +run an unpinned script, to make an unpinned machine declare the capability, or +to get a non-sha256 value past the check, is in scope. + +**Artifact handling.** Path traversal in artifact names or `?filename=`, a hash +that is not verified where the code claims it is, or a way to make a job read or +write outside the artifact directory. + +**The `web-*` workloads fetch arbitrary URLs from a job spec.** They are meant +to. A way to turn that into reading a local file, reaching a link-local metadata +address, or executing something on the executor host is in scope. + +**Credential handling.** Job specs carry credential *names*, never secrets, and +the values come from the Keychain or the environment of the machine that needs +them. A path where a secret ends up in a job spec, a result row, an uploaded +artifact or a log is in scope — including build logs, which are uploaded on +failure. + +**`FLEET_BIND` not doing what it says.** If the collector answers on an +interface the configuration excluded, that is a real bug, because it is the +control the whole posture rests on. + +**Anything that escapes the stated boundary**: a request that reaches the host +beyond the documented API, a device left in a modified state that the journals +do not record, or a way to get code execution on an executor from a job spec +alone. + +## What is out of scope + +- The absence of authentication, authorisation, rate limiting, TLS or audit + logging on the collector. +- That `POST /jobs` is open, or that `FLEET_DASH_TOKEN` does not protect it. +- Anything that requires being on the LAN or tailnet as a precondition and then + does what the API already documents. +- Denial of service by enqueueing many jobs. +- Findings from a scanner against a deployment you do not own. + +## Reporting + +Use GitHub's private advisory form: +**[Report a vulnerability](https://github.com/addisdev/fleet-runner/security/advisories/new)**. + +Please do not open a public issue for something in the in-scope list above. + +This is a personal project maintained by one person. Expect a first response +within a week, and expect the fix to be a commit rather than a coordinated +release. + +## Supported versions + +The tip of `main`. There are no maintained release branches, and a fix will land +on `main` and in the next tag rather than being backported. + +## What the design already does + +Worth knowing, because it is where a report is least likely to find something: + +- **Job specs never carry secrets**, and this is structural rather than + validated — an unauthenticated enqueue endpoint means a spec is not a place a + credential could safely live, so the agents read their own. +- **A build's failure log is uploaded anonymously**, because a log published + under the app's name would become what a nightly asking for `"latest"` picks + up. +- **A `serve` job's endpoint binds to loopback or the tailnet, never + `0.0.0.0`** — an unauthenticated inference server on a laptop's hotel wifi is + a different product to the one anybody asked for. +- **Dependabot is on for security alerts and security fixes only.** There is no + `dependabot.yml`, deliberately, so version-bump pull requests do not bury the + ones that matter.