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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.git
.github
target
*.md
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ __pycache__/
.env
.venv/
*.terraform
.terraform.*
.terraform.*
target/
3 changes: 3 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
15 changes: 9 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ GitHub template repository for creating new services on the Javabin platform.
| File | Purpose |
|------|---------|
| `app.yaml` | Platform service configuration — compute, routing, resources, auth |
| `Dockerfile` | Multi-stage build (Java/Temurin by default, adapt for your runtime) |
| `Dockerfile` | Multi-stage build (Java/Temurin by default, adapt for your runtime); runs as user 1000 |
| `pom.xml`, `mvnw`, `.mvn/`, `src/` | Minimal Spring Boot 4 app (Java 21): `GET /` and `GET /actuator/health` on port 8080 |
| `.github/workflows/deploy.yml` | CI entrypoint — calls `javabin.yml` reusable workflow |
| `README.md` | Starter README with getting-started steps |

## How to Use

1. Click **"Use this template"** on GitHub to create a new repo under `javaBin/`
2. Edit `app.yaml` — set your service name, team, compute settings, routing, and any resources
3. Ensure your team is registered in [javaBin/registry](https://github.com/javaBin/registry) (`teams/{name}.yaml`) and add the repo to the GitHub team named in `app.yaml` `team:` (CI verifies repo → team before vending credentials)
2. Ensure your team is registered in [javaBin/registry](https://github.com/javaBin/registry) (`teams/{name}.yaml`) and add the repo to the GitHub team named in `app.yaml` `team:` before the first push to `main` (CI verifies repo → team before vending credentials): `gh api -X PUT orgs/javaBin/teams/<team>/repos/javaBin/<repo> -f permission=push`
3. Edit `app.yaml` — set your service name, team, compute settings, routing, and any resources
4. Push to `main` — the platform CI builds, plans, reviews, and deploys automatically
5. Set any secret values: `brew install javaBin/tap/javabin`, `javabin aws setup` (SSO permission set `javabin-team-<team>`), then `javabin secret set <name>`

## app.yaml Fields

- `name` — service name (required, lowercase + hyphens, max 20 chars)
- `team` — owning team, lowercase letters only (max 12), must exist in the registry (required)
- `compute` — CPU, memory, port, desired count, health check path, `user` (default `"1000"`), `readonly_root_filesystem` (default `true`; only `/tmp` writable)
- `routing` — hostname one label under `javazone.no`, `java.no` or `javabin.no`, and ALB priority
- `compute` — CPU, memory, port, desired count, health check path (template: `/actuator/health`, what Spring Boot Actuator serves), `user` (default `"1000"`), `readonly_root_filesystem` (default `true`; only `/tmp` writable)
- `routing` — hostname one label under `javazone.no`, `java.no` or `javabin.no`, and optional ALB `priority` (the template omits it so the platform derives a unique one; a shared hard-coded value collides with `PriorityInUse`)
- `resources` — S3 buckets, DynamoDB tables / RDS PostgreSQL, SSM secrets (created as `PLACEHOLDER`, set with `javabin secret set`), SQS queues
- `auth` — Cognito: `internal`/`external` shorthand, or full form with `client: confidential|public|none`, `callback_urls` (https or `http://localhost`), `groups` (restricts sign-in), `env` (alias injected names)
- `environment` — custom environment variables
Expand All @@ -35,7 +36,9 @@ Full reference: [app.yaml reference](https://github.com/javaBin/platform/blob/ma

## Dockerfile

The default Dockerfile uses `eclipse-temurin:21` for a Java/Maven project. Replace it with your own if you use a different runtime (Node.js, Go, Python, etc.).
The default Dockerfile builds the bundled Spring Boot app with `./mvnw` on `eclipse-temurin:21` and runs the jar as user 1000 on port 8080. The platform runs containers non-root with a read-only root filesystem, so the app may only write to `/tmp`. Replace the Dockerfile if you use a different runtime (Node.js, Go, Python, etc.) and keep those rules.

Check a change locally: `./mvnw verify`, then `docker build -t t . && docker run --rm -p 8080:8080 --read-only --tmpfs /tmp t` and `curl localhost:8080/actuator/health`.

## CI

Expand Down
16 changes: 12 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# Multi-stage build — adjust base images for your runtime
# Multi-stage build: the bundled Spring Boot app (Java 21) via the Maven wrapper.
# Replace this file if you use another runtime; keep the runtime rules below.
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./mvnw -q package -DskipTests
# Resolve dependencies first so they stay cached across source changes.
COPY mvnw pom.xml ./
COPY .mvn .mvn
RUN ./mvnw -q -B dependency:go-offline
COPY src src
RUN ./mvnw -q -B package -DskipTests

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
# The platform runs the container as user 1000 (compute.user) with a read-only
# root filesystem where only /tmp is writable. Do the same here.
USER 1000
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
ENTRYPOINT ["java", "-Djava.io.tmpdir=/tmp", "-jar", "app.jar"]
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,34 @@ A Javabin platform service.

## Getting Started

Do these in order. CI checks that the repo belongs to the team in `app.yaml` before it hands out AWS credentials, so a push to `main` before steps 2 and 3 fails.

1. **Create from template**: Click "Use this template" on GitHub (repo under `javaBin/`)
2. **Register your team**: If not already registered, open a PR to [javaBin/registry](https://github.com/javaBin/registry) adding `teams/<team>.yaml` (or run `javabin register-team`). Merging creates the GitHub team and the team's AWS CI roles; members sign in to AWS with the SSO permission set `javabin-team-<team>`. Team names are lowercase letters only, max 12 chars.
3. **Add this repo to your GitHub team** — the one named in `app.yaml` `team:`; CI refuses to deploy otherwise:
3. **Add this repo to your GitHub team** (the one you will name in `app.yaml` `team:`) before the first push to `main`:
`gh api -X PUT orgs/javaBin/teams/<team>/repos/javaBin/<repo> -f permission=push`
4. **Customize `app.yaml`**: Set your service name, team, compute, routing, and any resources/auth
4. **Customize `app.yaml`**: Set your service name, team, compute, routing, and any resources/auth. Leave out `routing.priority`; the platform picks a unique one.
5. **Push to main**: The platform CI pipeline builds, plans, reviews, and deploys automatically. Pull requests get a Terraform plan and review comment.

No repository secrets are needed. `.github/workflows/deploy.yml` must keep its `permissions:` block (`id-token: write`, `contents: write`, `pull-requests: write`). Its `if:` only stops the template repo itself from deploying; it is true in your repo.

## The App

The template ships a minimal Spring Boot 4 app (Java 21, Maven wrapper) that deploys as-is:

- `GET /` answers with a greeting; `GET /actuator/health` is the health check `app.yaml` points at (`compute.health_check`).
- It listens on 8080 (`compute.port`), runs as user 1000 and only writes to `/tmp`, matching the platform's non-root, read-only-root-filesystem container.

Run it locally:

```bash
./mvnw spring-boot:run # or: ./mvnw verify (runs the tests)
docker build -t my-service . && docker run --rm -p 8080:8080 --read-only --tmpfs /tmp my-service
curl localhost:8080/actuator/health # {"status":"UP"}
```

Replace the code with your own. If you change the port or health path, change `compute.port` / `compute.health_check` too.

## Secrets

`resources.secrets` entries are created with the value `PLACEHOLDER` on the first deploy. Set real values with the [javabin CLI](https://github.com/javaBin/javabin-cli) from this repo:
Expand Down
7 changes: 5 additions & 2 deletions app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ compute:
memory: 1024 # MB, must be a valid Fargate combination with cpu
port: 8080 # container port your app listens on (platform default: 8000)
desired_count: 1 # number of running tasks
health_check: /health
health_check: /actuator/health # Spring Boot Actuator; change if your app serves another path
# user: "1000" # container user (default "1000", non-root)
# readonly_root_filesystem: true # default true — only /tmp is writable; set false if the app writes elsewhere

# ALB routing — omit for a worker with no load balancer
routing:
host: my-service.javazone.no # one label under javazone.no, java.no or javabin.no
priority: 100 # unique across all apps (1-50000)
# priority is left out on purpose: the platform derives a unique ALB listener
# rule priority for each app. A hard-coded value is shared by every repo made
# from this template and collides on deploy (PriorityInUse). Only set
# `priority:` (unique, 1-50000) if you must control rule evaluation order.

# Infrastructure resources (optional) — auto-wired to your container
# resources:
Expand Down
Loading