# Contributing to Islandr ## Bug reports and ideas — yes please Open a [GitHub Issue](https://github.com/chriscohnen/islandr/issues) for: - Bug reports (include steps to reproduce, OS, Java version if on JVM mode) - Feature ideas or suggestions - Questions about setup or behaviour ## Pull requests — not accepted Islandr is a solo project. I use agentic coding to iterate fast and I maintain full control over architecture and code style. Pull requests will be closed without merge, no matter how good the code is. This is not a reflection on your contribution — it's a deliberate project boundary. If you find a bug and want to share a fix, post it as an Issue with the patch as a code block. I'll apply it myself if it fits. ## Forks EUPL-1.2 is a copyleft licence — you are free to fork, modify, and distribute under the same licence. If you build something significant on top of Islandr, I'd love to hear about it in an Issue. ## Running it locally Dev server (Quarkus live coding): ```bash ./gradlew quarkusDev # → http://localhost:8080 ``` The `%dev` profile ships with `islandr.admin.user=admin` / `islandr.admin.password=admin` so the local login just works. **In prod the password has no default** — operators must set `ISLANDR_ADMIN_PASSWORD` as an env var, otherwise `/api/v1/auth/login` returns HTTP 503 ("local admin login disabled"). This is deliberate: a known default in containers is a security hole; a loud failure is not. Tests (1000+, runs in ~25 s after warm start): ```bash ./gradlew test ``` The test profile uses an in-memory SQLite that's wiped per run (`clean-at-start=true`) and a `MockWgAdapter` so no `wg` binary is needed. ## Repository layout ``` islandr/ ├── README.md # this file ├── CLAUDE.md # guidance for Claude Code ├── build.gradle.kts # Gradle 9.1 / Kotlin DSL ├── docs/ │ ├── prd.md # Product Requirements Document │ ├── install.md # Installation guide (native binary, Docker) │ ├── install/ # setup-hub.sh, reverse-proxy.md, hardening.md, identity-microsoft365.md, fail2ban.md │ ├── faq.md # Operational FAQ (logs, wg/nft troubleshooting) │ ├── arc42/ # Architecture documentation (arc42, 12 chapters) │ └── adr/ # Architecture Decision Records (Nygard + Pugh) │ └── README.md # ADR index — one file per decision, numbered 0001+ ├── architecture/ │ ├── workspace.dsl # C4 model (Structurizr DSL) — source of diagrams │ ├── docs/ # Markdown pages rendered into the interactive C4 site │ │ ├── 01-overview.md # home / entry point of the architecture portal │ │ └── 02-roadmap.md # roadmap page │ └── diagrams/ # generated C4 PNGs + .puml, embedded in arc42 ├── scripts/ │ ├── update.sh # download, verify, swap the binary, roll back if it fails │ ├── backup.sh # gzip-compressed, rotated SQLite backup via `sqlite3 .backup` │ └── check-templates.mjs # compiles every inline Vue template in CI (no npm, uses the vendored Vue) ├── src/ │ ├── main/java/de/chriscohnen/islandr/ │ │ ├── acl/ # RBAC0: Roles, Resources, Ports/PortGroups, Sites, ACL matrix, "Mein Zugang", port reservations (#72) │ │ ├── acme/ # hand-rolled RFC 8555 ACME client — Let's Encrypt auto-provisioning │ │ ├── admin/ # config export/import, version check │ │ ├── apikey/ # admin-issued API keys for the external automation API (ADR-0026) │ │ ├── audit/ # audit log (entity, diff, resource, service) │ │ ├── auth/ # Session, SessionFilter, AdminBootstrap, AuthResource, OidcAuthResource │ │ ├── crypto/ # EncryptionService — AES-256-GCM for secrets/keys at rest │ │ ├── dashboard/ # dashboard aggregation (DTO + resource) │ │ ├── discovery/ # unprivileged CIDR scan for device discovery (ADR-0014), the link-scope gate that skips mDNS/LLMNR for off-link targets, and MAC/OUI vendor lookup (#76) │ │ ├── dns/ # hand-rolled DNS wire format: peer-facing resource-name resolver (ADR-0023), plus PTR/mDNS/LLMNR/NetBIOS/SSDP lookups feeding discovery's hostname and MAC suggestions (#45, #48, #76) │ │ ├── external/ # /api/external/v1 facade: API-key auth, peers/users/sites/resources/roles (ADR-0026) │ │ ├── firewall/ # nftables RuleBuilder + adapters (real/mock/dry-run) + RulesetService │ │ ├── hosthealth/ # hub CPU/memory/swap sampler, hand-rolled from /proc (issue #73) │ │ ├── identity/ # OidcProvider + OidcCustomProvider (issue #69), JwksCache, IdTokenVerifier, OidcLoginService, AvatarFetcher │ │ ├── network/ # network diagnostics: ping/tracepath/mtr over an unprivileged shell (ADR-0025) │ │ ├── peer/ # Peer entity + DTO + Resource + Service + IpSubnet + QrService │ │ ├── proxy/ # Docker socket-proxy client + reconciler (ADR-0012) │ │ ├── settings/ # singleton settings (WG topology, retention mode, hub geocoding) │ │ ├── tls/ # built-in TLS termination, cert hot-swap (ADR-0015) │ │ ├── user/ # User + Resource + AvatarService + Google Workspace import + access expiry (#53) │ │ ├── validation/ # @ValidIpAddress / @ValidCidr custom validators │ │ ├── webhook/ # outbound event webhooks (issue #68) │ │ ├── wg/ # WgAdapter (real shells out, mock for dev/CI) │ │ └── NativeReflectionConfig.java # GraalVM native-image reflection registration │ ├── main/resources/ │ │ ├── application.properties │ │ ├── data/oui-vendors.csv # bundled IEEE MA-L registry — MAC prefix → vendor, resolved offline (#76) │ │ ├── db/migration/ # Flyway migrations V1–V76, portable SQL │ │ └── META-INF/resources/ # static frontend assets │ │ ├── index.html # importmap, single page │ │ ├── favicon.svg # cyan island + waves │ │ ├── api/openapi.yml # hand-written OpenAPI spec for the external API facade (ADR-0026) │ │ ├── css/ # tokens.css + components.css + app.css │ │ └── js/ # Vue 3 modules, no build │ └── test/ # 903 tests, JUnit 5 + RestAssured + AssertJ ```