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 .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/secret-scan-gate.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/pre-pr-gate.sh"
Expand Down
63 changes: 57 additions & 6 deletions .github/workflows/build-on-ubuntu.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
name: Ubuntu CI

on: push
# Triggers:
# * push to a default or release-line branch — those ending in `master` or
# `main`, the same set `increment-guard.yml` guards as PR bases (e.g.
# `master`, `2.x-jdk8-master`). These post-merge runs are the only source
# of base-branch coverage, since `Publish` runs `publish -x test` and
# uploads none; `target: auto` in `.codecov.yml` compares each pull request
# against its base baseline.
# * pull_request — gates a change on its merge result, not the branch tip.
on:
push:
branches:
- '**master'
- '**main'
pull_request:

jobs:
build:
name: Build on Ubuntu
runs-on: ubuntu-latest
concurrency: # Avoid canceling in-progress runs for the same branch.
group: ubuntu-ci-${{ github.ref }}
cancel-in-progress: false

steps:
- uses: actions/checkout@v6
Expand All @@ -19,13 +35,24 @@ jobs:

- uses: gradle/actions/setup-gradle@v6

# Mirrors the pagefile step in build-on-windows.yml. The Linux runner
# ships with effectively no swap, so a memory peak becomes an instant
# OOM kill; this gives the kernel somewhere to fall back to.
- name: Add swap space
uses: pierotofy/set-swap-space@v1.0
with:
swap-size-gb: 8

- name: Build project, run tests
shell: bash
run: ./gradlew build --stacktrace

# `build` does not run Dokka — its tasks are gated to the publishing
# graph — so `dokkaGenerate` is appended to surface documentation
# warnings on each push, before merge, instead of only in the post-merge
# `Publish` job. `failOnWarning` is enabled in the Dokka setup.
- name: Build project, run tests, and check documentation
shell: bash
run: ./gradlew build dokkaGenerate --stacktrace
# warnings before merge, instead of only in the post-merge `Publish`
# job. `failOnWarning` is enabled in the Dokka setup.
- name: Check documentation
run: ./gradlew dokkaGenerate --stacktrace

# See: https://github.com/marketplace/actions/junit-report-action
- name: Publish Test Report
Expand All @@ -35,7 +62,31 @@ jobs:
report_paths: '**/build/test-results/**/TEST-*.xml'
require_tests: true # will fail workflow if test reports not found

# Probe whether the upload token is available without exposing its value
# to the build/test steps. Scoping `CODECOV_TOKEN` to this trivial step
# (and to the upload step's `with.token`) keeps PR-authored code in
# `./gradlew build` from ever seeing the secret. The `secrets` context is
# not available in a step `if:`, so the upload gates on this output.
- name: Detect Codecov token
id: codecov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
if [ -n "$CODECOV_TOKEN" ]; then
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "available=false" >> "$GITHUB_OUTPUT"
fi

# On `push` (master) always upload — these runs are the only source of
# the `target: auto` baseline, so an absent token there is a
# misconfiguration that should fail loudly rather than silently stop
# refreshing coverage. On `pull_request`, skip when the token is absent:
# forked and Dependabot PRs run without secrets, and `fail_ci_if_error`
# would otherwise redden a healthy PR (coverage gating is meaningless
# there anyway).
- name: Upload code coverage report
if: steps.codecov.outputs.available == 'true' || github.event_name == 'push'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Secret scan

# Defense-in-depth behind the local `secret-scan` pre-commit hook and the
# `.gitignore` secret patterns: if a credential is committed despite those, this
# fails the pull request before it can merge. Distributed to every Spine repo by
# `./config/pull`.

on:
pull_request:
push:
branches:
- master
- main

permissions:
contents: read

jobs:
gitleaks:
name: gitleaks
runs-on: ubuntu-latest
env:
# Pinned gitleaks version — bump through the usual dependency-update process.
GITLEAKS_VERSION: "8.21.2"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Full history so a pull request's commit range can be scanned.
fetch-depth: 0

- name: Install gitleaks
# Run gitleaks as the runner user against the checkout it owns — no
# container, so no "dubious ownership" git error and no GitHub Action
# org-licence requirement.
run: |
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xzf - gitleaks
./gitleaks version

- name: Scan
env:
EVENT: ${{ github.event_name }}
BASE: ${{ github.event.pull_request.base.sha }}
HEAD: ${{ github.event.pull_request.head.sha }}
BEFORE: ${{ github.event.before }}
AFTER: ${{ github.sha }}
run: |
if [ "$EVENT" = pull_request ]; then
# Scan the PR's own commit RANGE: a secret added in one commit and
# deleted in a later commit of the same PR is still caught (a
# working-tree scan would miss it, yet merging keeps the secret-bearing
# commit reachable), while already-rotated secrets in older history
# outside base..head are not re-flagged.
./gitleaks git --log-opts="$BASE..$HEAD" --redact --verbose --exit-code=1 .
else
# Push to a default branch: scan the pushed commit RANGE (before..after)
# so an add-then-remove batch is caught here too, not only on PRs — the
# leaked commit would otherwise stay reachable on the default branch. A
# branch's first push reports an all-zero `before` (no range); fall back
# to a working-tree scan then.
if [ -n "$BEFORE" ] && [ "$BEFORE" != "0000000000000000000000000000000000000000" ]; then
./gitleaks git --log-opts="$BEFORE..$AFTER" --redact --verbose --exit-code=1 .
else
# Branch's first push (all-zero `before`): no range to diff against, so
# scan the whole history reachable from the pushed tip as the initial
# import — an add-then-remove within those commits is still caught.
./gitleaks git --log-opts="$AFTER" --redact --verbose --exit-code=1 .
fi
fi
74 changes: 72 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# >>> shared config (managed by ./config/pull -- do not edit inside this block) >>>
#
# Copyright 2025, TeamDev. All rights reserved.
#
Expand Down Expand Up @@ -103,14 +104,48 @@ gradle-app.setting
# Spine internal directory for storing intermediate artifacts
**/.spine/**

# Login details to Maven repository.
# Each workstation should have developer's login defined in this file.
# ---------------------------------------------------------------------------
# Secrets — NEVER commit these.
#
# Encrypted credentials live under `.github/keys/*.gpg` and ARE committed.
# `config/scripts/decrypt.sh` turns each into its PLAINTEXT twin at build / CI /
# publish time (e.g. `spine-dev-framework-ci.json.gpg` -> `spine-dev.json`). The
# decrypted twins below — and any private key or service-account file — must stay
# out of Git. The shared `secret-scan` pre-commit hook is the backstop if one ever
# slips past these patterns.
# ---------------------------------------------------------------------------

# Maven repository login details; each workstation defines its own.
credentials.tar
credentials.properties
cloudrepo.properties
deploy_key_rsa
gcs-auth-key.json

# Decrypted Google / GCP service-account keys (plaintext twins of *.gpg).
spine-dev.json
spine-dev-*.json
maven-publisher.json
firebase-sa.json
*-sa.json
*service-account*.json

# Decrypted credential property files and portal / publisher secrets.
*.secret.properties

# Private SSH keys (public keys are *.pub and remain committable).
*_rsa
*_dsa
*_ecdsa
*_ed25519
id_rsa
id_dsa
id_ecdsa
id_ed25519

# ...but always keep the committed ENCRYPTED forms.
!*.gpg

# Log files
*.log

Expand Down Expand Up @@ -152,3 +187,38 @@ __pycache__/
docs/_preview/node_modules/
docs/_preview/public/
docs/_preview/resources/
# <<< shared config <<<

# >>> repo-local entries (preserved across ./config/pull) >>>
!.idea/misc.xml
!.idea/codeStyleSettings.xml
!.idea/codeStyles/
!.idea/copyright/
!**/src/**/build/**
!gradle-wrapper.jar
# Login details to Maven repository.
# Each workstation should have developer's login defined in this file.
# <<< repo-local entries <<<

# >>> secret ignores re-asserted last (managed by ./config/pull -- do not edit) >>>
credentials.tar
credentials.properties
cloudrepo.properties
deploy_key_rsa
gcs-auth-key.json
spine-dev.json
spine-dev-*.json
maven-publisher.json
firebase-sa.json
*-sa.json
*service-account*.json
*.secret.properties
*_rsa
*_dsa
*_ecdsa
*_ed25519
id_rsa
id_dsa
id_ecdsa
id_ed25519
# <<< secret ignores <<<
8 changes: 6 additions & 2 deletions .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2025, TeamDev. All rights reserved.
* Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,13 +36,13 @@ object GoogleApis {
const val client = "com.google.api-client:google-api-client:1.32.2"

// https://github.com/googleapis/api-common-java
const val common = "com.google.api:api-common:2.1.1"
const val common = "com.google.api:api-common:2.64.0"

// https://github.com/googleapis/java-common-protos
const val commonProtos = "com.google.api.grpc:proto-google-common-protos:2.7.0"
const val commonProtos = "com.google.api.grpc:proto-google-common-protos:2.72.0"

// https://github.com/googleapis/gax-java
const val gax = "com.google.api:gax:2.7.1"
const val gax = "com.google.api:gax:2.80.0"

// https://github.com/googleapis/java-iam
const val protoAim = "com.google.api.grpc:proto-google-iam-v1:1.2.0"
Expand All @@ -52,7 +52,7 @@ object GoogleApis {

// https://github.com/googleapis/google-auth-library-java
object AuthLibrary {
const val version = "1.3.0"
const val version = "1.47.0"
const val credentials = "com.google.auth:google-auth-library-credentials:$version"
const val oAuth2Http = "com.google.auth:google-auth-library-oauth2-http:$version"
}
Expand Down
21 changes: 12 additions & 9 deletions buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2025, TeamDev. All rights reserved.
* Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,18 +26,21 @@

package io.spine.dependency.lib

/**
* https://github.com/googleapis/google-cloud-java
*/
@Suppress("unused", "ConstPropertyName")
object GoogleCloud {

// https://github.com/googleapis/java-core
const val core = "com.google.cloud:google-cloud-core:2.3.3"
// https://github.com/googleapis/google-cloud-java/tree/main/sdk-platform-java/java-core
const val core = "com.google.cloud:google-cloud-core:2.71.0"

// https://github.com/googleapis/java-pubsub/tree/main/proto-google-cloud-pubsub-v1
const val pubSubGrpcApi = "com.google.api.grpc:proto-google-cloud-pubsub-v1:1.97.0"
// https://github.com/googleapis/google-cloud-java/tree/main/java-pubsub/proto-google-cloud-pubsub-v1
const val pubSubGrpcApi = "com.google.api.grpc:proto-google-cloud-pubsub-v1:1.151.0"

// https://github.com/googleapis/java-trace
const val trace = "com.google.cloud:google-cloud-trace:2.1.0"
// https://github.com/googleapis/google-cloud-java/tree/main/java-trace
const val trace = "com.google.cloud:google-cloud-trace:2.93.0"

// https://github.com/googleapis/java-datastore
const val datastore = "com.google.cloud:google-cloud-datastore:2.2.1"
// https://github.com/googleapis/google-cloud-java/tree/main/java-datastore
const val datastore = "com.google.cloud:google-cloud-datastore:2.31.2"
}
34 changes: 34 additions & 0 deletions buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.dependency.lib

// https://github.com/perfmark/perfmark
@Suppress("unused", "ConstPropertyName")
object PerfMark {
private const val version = "0.27.0"
const val api = "io.perfmark:perfmark-api:$version"
}
Loading
Loading