diff --git a/.claude/hooks/block-token-read.sh b/.claude/hooks/block-token-read.sh new file mode 100755 index 0000000..b8afc6a --- /dev/null +++ b/.claude/hooks/block-token-read.sh @@ -0,0 +1,14 @@ +#!/bin/bash +FILE_PATH=$(jq -r '.tool_input.file_path // ""' < /dev/stdin) + +if [[ "$FILE_PATH" == *".devcontainer/github-token"* ]]; then + jq -n '{ + hookSpecificOutput: { + hookEventName: "PreToolUse", + permissionDecision: "deny", + permissionDecisionReason: "Access to .devcontainer/github-token is blocked — it contains secrets" + } + }' +else + exit 0 +fi diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..c18e018 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-token-read.sh" + } + ] + } + ] + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..6ac91d6 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +{ + "name": "Montonio Java SDK", + "image": "mcr.microsoft.com/devcontainers/java:17", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": {} + }, + "containerEnv": { + "CLAUDE_CONFIG_DIR": "/home/vscode/.claude" + }, + "mounts": [ + "source=montonio-sdk-claude-settings,target=/home/vscode/.claude,type=volume" + ], + "postCreateCommand": "bash .devcontainer/setup.sh", + "postStartCommand": "bash .devcontainer/gh-auth.sh" +} diff --git a/.devcontainer/gh-auth.sh b/.devcontainer/gh-auth.sh new file mode 100755 index 0000000..086acc6 --- /dev/null +++ b/.devcontainer/gh-auth.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Authenticate GitHub CLI using a personal access token stored in +# .devcontainer/github-token. Runs on every container start so that +# gh and git credentials stay configured across restarts. + +set -euo pipefail + +TOKEN_FILE="$(dirname "$0")/github-token" + +if [ ! -f "$TOKEN_FILE" ]; then + echo "No GitHub token found. To enable gh CLI auth:" + echo " 1. Create a file at .devcontainer/github-token" + echo " 2. Paste a GitHub PAT with the scopes you need (e.g. repo, read:org)" + echo " 3. Rebuild or restart the container" + echo " (This file is already in .gitignore and will not be committed.)" + exit 0 +fi + +TOKEN_PERMS="$(stat -c '%a' "$TOKEN_FILE" 2>/dev/null || stat -f '%Lp' "$TOKEN_FILE")" +if [ "$TOKEN_PERMS" != "600" ]; then + echo "WARNING: $TOKEN_FILE permissions are $TOKEN_PERMS; fixing to 600." + chmod 600 "$TOKEN_FILE" +fi + +TOKEN=$(cat "$TOKEN_FILE" | tr -d '[:space:]') + +if [ -z "$TOKEN" ]; then + echo "WARNING: .devcontainer/github-token exists but is empty. Skipping gh auth." + exit 0 +fi + +if gh auth status >/dev/null 2>&1; then + echo "GitHub CLI already authenticated." + exit 0 +fi + +if ! printf '%s\n' "$TOKEN" | gh auth login --with-token; then + echo "WARNING: GitHub CLI authentication failed. Continuing without gh auth." + exit 0 +fi + +gh auth setup-git || echo "WARNING: Failed to configure git credential helper via gh." +echo "GitHub CLI authenticated and git credentials configured." diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 0000000..5711e3b --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "==> Fixing volume permissions..." +sudo chown -R vscode:vscode /home/vscode/.claude + +echo "==> Installing Claude Code CLI..." +npm install -g @anthropic-ai/claude-code + +echo "==> Configuring shell aliases..." +grep -qxF 'alias yolo="claude --dangerously-skip-permissions"' ~/.bashrc || \ + echo 'alias yolo="claude --dangerously-skip-permissions"' >> ~/.bashrc + +echo "==> Pre-warming Gradle dependency cache..." +./gradlew dependencies --no-daemon + +echo "==> Setup complete!" diff --git a/.gitignore b/.gitignore index 05d7676..d4e4f36 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /build /.gradle .DS_Store +.devcontainer/github-token diff --git a/CLAUDE.md b/CLAUDE.md index 4607748..8382e33 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,6 +19,10 @@ Requires Java 17 (managed via `.sdkmanrc`). Uses Gradle 9.4.1 with Groovy DSL. ./gradlew test --tests 'com.example.MyTest.myMethod' # single test ``` +## Devcontainer + +A devcontainer configuration is provided in `.devcontainer/devcontainer.json`. It includes Java 17 (Temurin), Gradle (via wrapper), and GitHub CLI. Open the project in any devcontainer-compatible tool (VS Code, IntelliJ, GitHub Codespaces, Claude Code) to get a ready-to-use environment. + ## Gradle Structure Build is split across files following BitWeb conventions: diff --git a/README.md b/README.md new file mode 100644 index 0000000..87d21b9 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Montonio Java SDK + +A type-safe Java client for the [Montonio](https://montonio.com) payment gateway REST API (V2 + Stargate). Covers payment order lifecycle, payment method discovery, and JWT webhook/return validation. + +## Requirements + +- Java 17+ +- Gradle 9.4.1 (included via wrapper) + +## Getting Started + +### Using a Devcontainer (recommended) + +The project includes a [devcontainer](.devcontainer/devcontainer.json) configuration with Java 17, Gradle via the wrapper (`./gradlew`), and GitHub CLI. Open the project in any devcontainer-compatible tool: + +- **VS Code** — install the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension, then _Reopen in Container_ +- **IntelliJ IDEA** — open the project and follow the [Dev Containers integration](https://www.jetbrains.com/help/idea/connect-to-devcontainer.html) guide +- **GitHub Codespaces** — click _Code > Codespaces > New codespace_ on the repository page +- **CLI** — using the [Dev Container CLI](https://github.com/devcontainers/cli): + ```bash + devcontainer up --workspace-folder . + devcontainer exec --workspace-folder . bash + ``` + +### Local Setup + +Install Java 17 via [SDKMAN](https://sdkman.io/): + +```bash +sdk env install +``` + +## Build & Test + +```bash +./gradlew build # full build +./gradlew test # all tests +./gradlew unitTest # unit tests only +./gradlew integrationTest # integration tests only +./gradlew testAndReport # all tests + JaCoCo coverage reports +``` + +## License + +[MIT](LICENSE)