diff --git a/.github/actions/build-apm-jar/action.yml b/.github/actions/build-apm-jar/action.yml index 7c4b30879..3ac1a796a 100644 --- a/.github/actions/build-apm-jar/action.yml +++ b/.github/actions/build-apm-jar/action.yml @@ -13,14 +13,14 @@ runs: cd .. - name: Capture custom jar - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7 with: name: newrelic-artifact path: | newrelic-java-agent/newrelic-java/build/zips/newrelic.zip - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # pin@v6 with: role-to-assume: arn:aws:iam::280901927509:role/github-actions/repo aws-region: us-east-2 diff --git a/.github/actions/setup-environment-inst-verifier/action.yml b/.github/actions/setup-environment-inst-verifier/action.yml index 3ec3aadd7..0f4ad11b3 100644 --- a/.github/actions/setup-environment-inst-verifier/action.yml +++ b/.github/actions/setup-environment-inst-verifier/action.yml @@ -13,7 +13,7 @@ runs: steps: - name: Set up Javas - uses: actions/setup-java@v3 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # pin@v5 with: distribution: 'temurin' java-version: | @@ -45,7 +45,7 @@ runs: - name: Configure AWS Credentials if: ${{ inputs.apm-aws-secret-access-key != '' }} - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # pin@v6 with: aws-access-key-id: ${{ inputs.apm-aws-access-key-id }} aws-secret-access-key: ${{ inputs.apm-aws-secret-access-key }} diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 58f3abbab..e561ee23b 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -32,7 +32,7 @@ runs: steps: - name: Set up Javas - uses: actions/setup-java@v4 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # pin@v5 with: distribution: 'temurin' java-version: | @@ -54,7 +54,7 @@ runs: cat gradle.properties.gha >> gradle.properties - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # pin@v6 - name: Setup Gradle options shell: bash @@ -62,13 +62,13 @@ runs: # Restore the maven cache - name: Cache local Maven repository - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ github.run_id }} - name: Checkout APM agent - uses: actions/checkout@v3 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: repository: ${{ inputs.apm-repo }} ref: ${{ inputs.apm-branch }} @@ -97,7 +97,7 @@ runs: - name: Configure AWS Credentials if: ${{ inputs.apm-aws-secret-access-key != '' }} - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # pin@v6 with: aws-access-key-id: ${{ inputs.apm-aws-access-key-id }} aws-secret-access-key: ${{ inputs.apm-aws-secret-access-key }} diff --git a/.github/workflows/X-Reusable-Build-Security-Agent.yml b/.github/workflows/X-Reusable-Build-Security-Agent.yml index f1be7b393..13ec8a3db 100644 --- a/.github/workflows/X-Reusable-Build-Security-Agent.yml +++ b/.github/workflows/X-Reusable-Build-Security-Agent.yml @@ -69,7 +69,7 @@ jobs: steps: - name: Checkout CSEC Repo - uses: actions/checkout@v3 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ github.ref }} diff --git a/.github/workflows/X-Reusable-VerifyInstrumentation.yml b/.github/workflows/X-Reusable-VerifyInstrumentation.yml index 95eb89536..3510eb91e 100644 --- a/.github/workflows/X-Reusable-VerifyInstrumentation.yml +++ b/.github/workflows/X-Reusable-VerifyInstrumentation.yml @@ -29,7 +29,7 @@ jobs: outputs: modules: ${{ steps.set-modules.outputs.modules }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ inputs.ref }} @@ -58,7 +58,7 @@ jobs: # GHA's IDE think the line below is broken. It is not. matrix: ${{ fromJson(needs.read-modules.outputs.modules) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/build-integrated-jar.yml b/.github/workflows/build-integrated-jar.yml index 53e726a05..feeb5997e 100644 --- a/.github/workflows/build-integrated-jar.yml +++ b/.github/workflows/build-integrated-jar.yml @@ -58,7 +58,7 @@ jobs: run: echo "${{ toJSON(github.event.inputs) }}" - name: Checkout CSEC Java agent - uses: actions/checkout@v3 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ github.ref }} diff --git a/.github/workflows/dependency-submission.yml b/.github/workflows/dependency-submission.yml index 744a8c3a9..5c5484088 100644 --- a/.github/workflows/dependency-submission.yml +++ b/.github/workflows/dependency-submission.yml @@ -14,9 +14,9 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # pin@v5 with: distribution: 'temurin' java-version: 8 diff --git a/.github/workflows/publish-to-maven.yml b/.github/workflows/publish-to-maven.yml index 1608d2efa..b420feeb0 100644 --- a/.github/workflows/publish-to-maven.yml +++ b/.github/workflows/publish-to-maven.yml @@ -96,7 +96,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout APM agent - uses: actions/checkout@v3 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ github.ref }} diff --git a/.github/workflows/repolinter.yml b/.github/workflows/repolinter.yml index 145c3c041..b7389b3ad 100644 --- a/.github/workflows/repolinter.yml +++ b/.github/workflows/repolinter.yml @@ -26,7 +26,7 @@ jobs: return data.data && data.data.default_branch === context.ref.split('/').slice(-1)[0] - name: Checkout Self if: ${{ steps.default-branch.outputs.result == 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 - name: Run Repolinter if: ${{ steps.default-branch.outputs.result == 'true' }} uses: newrelic/repolinter-action@v1 diff --git a/.github/workflows/verify-instrumentation-single.yml b/.github/workflows/verify-instrumentation-single.yml index cead578bd..476992e7a 100644 --- a/.github/workflows/verify-instrumentation-single.yml +++ b/.github/workflows/verify-instrumentation-single.yml @@ -27,7 +27,7 @@ jobs: run: echo "${{ toJSON(github.event.inputs) }}" - name: Checkout CSEC Java agent - uses: actions/checkout@v3 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6 with: ref: ${{ github.ref }} diff --git a/docs/LOCAL_DEVELOPMENT.md b/docs/LOCAL_DEVELOPMENT.md new file mode 100644 index 000000000..fe27552b0 --- /dev/null +++ b/docs/LOCAL_DEVELOPMENT.md @@ -0,0 +1,87 @@ +# Building and Running csec-java-agent Locally + +This doc walks through building csec-java-agent agent end to end on a dev machine: the +base APM Java agent and the security agent. +## 1. Overview + +`csec-java-agent` is built and published as a dependency for use in `newrelic-java-agent` only - it is not a standalone artifact you run by itself. + +It depends on artifacts published by a fork of the APM Java agent: + +- Repo: `k2io/newrelic-java-agent` (a New Relic fork, org `k2io`) +- Branch to use: `csec-dev` +- Referred to informally below as **"K2-JavaAgent"** + +## 2. Prerequisites + +- Install java AdoptOpenJDK 8 and java versions 11 and 17 as well. +- **JDK 8 is required** to build both repos. Configure it in + `~/.gradle/gradle.properties` file: + ```properties + jdk8=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home + ``` +- Two repos checked out locally: + 1. `newrelic-java-agent` - https://github.com/k2io/newrelic-java-agent, + checked out on branch `csec-dev`. + 2. `csec-java-agent` - https://github.com/newrelic/csec-java-agent. +- `./gradlew` works from each repo's own root. + +## 3 - Build the Dependencies from APM Java Agent + +All commands in this section run from the **`newrelic-java-agent` root** +(k2io fork, `csec-dev` branch). + +### Step 1 - Publish prerequisite modules to Maven local + +```bash +./gradlew clean \ + :newrelic-api:publishToMavenLocal \ + :agent-bridge:publishToMavenLocal \ + :agent-bridge-datastore:publishToMavenLocal \ + :newrelic-weaver-api:publishToMavenLocal \ + :newrelic-weaver:publishToMavenLocal \ + :newrelic-weaver-scala:publishToMavenLocal \ + :newrelic-weaver-scala-api:publishToMavenLocal \ + --parallel +``` + +## 4 - Build the CSEC Java Agent + +All commands in this section run from the **`csec-java-agent` root**. +Publish API and agent locally. + +### 4.1 - Build and publish the security API + +```bash +./gradlew ${GRADLE_OPTIONS} :newrelic-security-api:publishToMavenLocal \ + --parallel +``` + +### 4.2 - Build and publish the security agent + +```bash +./gradlew ${GRADLE_OPTIONS} publishToMavenLocal \ + --parallel +``` + +### Build the standalone security agent jar [OPTIONAL] + +```bash +./gradlew clean jar --parallel +``` + +Artifacts land at: + +``` +newrelic-security-agent/build/libs +``` + +Only needed if you want the jar itself rather than just installing to Maven +local for `newrelic-java-agent` to pick up. +## References + +- `csec-java-agent/README.md` - "Building" section (source for Part 2 baseline commands) +- `csec-java-agent/.github/actions/publish-csec-local/action.yml` +- `newrelic-java-agent/README.md` - "Building" section (source for Part 1 baseline commands) +- `newrelic-java-agent/.github/actions/setup-environment/action.yml` - `GRADLE_OPTIONS` definition +- [RELEASE.md](RELEASE.md) - build/package/publish steps and release CI workflows diff --git a/docs/RELEASE.md b/docs/RELEASE.md new file mode 100644 index 000000000..0f65ccb1c --- /dev/null +++ b/docs/RELEASE.md @@ -0,0 +1,73 @@ +# Releasing csec-java-agent + +Step-by-step guide for release of csec-java-agent, plus what the GitHub Actions +workflows do at each stage. csec-java-agent is published as a dependency consumed by +`newrelic-java-agent` - releasing it does not produce a +standalone runnable artifact. + +## 1. Pre-release + +1. Confirm you're releasing off `main` - every publish workflow below builds from the pushed/ + tagged ref, so a stray branch produces a stray artifact. +2. Bump CSEC version +- `agentVersion` in `gradle.properties` (root of this repo). +- Also update `securityAgentVersion` in `newrelic-java-agent/gradle.properties` (in k2-JavaAgent). +3. Update `Changelog.md` (Keep a Changelog format - see existing entries for style). +4. Open/merge the version-bump + changelog PR to `main` like any other change. This PR triggers + the same CI gates as any PR (section 2) plus, once merged, a snapshot publish (section 3). + +## 2. CI gates (run automatically on every PR and push to `main`) + +| Check | Workflow | What it does | +|---|---|---| +| Unit tests | `X-Reusable-Build-Security-Agent.yml` -> `.github/actions/unit-test` | Run unit tests and retries up to 4 times on failure before the job is marked failed. | +| CVE / dependency check | `dependency-submission.yml` | On every PR to `main`: submits the Gradle dependency graph (`newrelic-security-agent`/`newrelic-security-api` projects), then runs `actions/dependency-review-action` with `fail-on-severity: low` - **any newly-introduced CVE at low severity or above fails the PR check.** | +| Instrumentation verification | `verify-instrumentation.yml` -> `X-Reusable-VerifyInstrumentation.yml` | Not PR-gated - runs nightly (`cron: '0 0 * * *'`) against `main`, or on demand (`workflow_dispatch`/`workflow_call`). Reads every module under `instrumentation-security/` from `settings.gradle`, splits them across a paged matrix (GHA's 255-job matrix limit), and runs `:instrumentation::verifyInstrumentation` on **Java 17** for each. A Slack alert (`SLACK_WEBHOOK_URL_INST_VERIFIER`) fires on failure. | +## 3. Snapshot publish (automatic, no action needed) + +Every push to `main` runs `publish-main-snapshot-to-maven.yml`, which calls the reusable +`publish-to-maven.yml` with `is-release=false`, `csec-run-unittest=true`, +`csec-run-instrumentation-verify=true`. Unit tests and instrumentation verification must pass +before it publishes `newrelic-security-api` and the CSEC agent to the Maven **snapshot** +repository via `./gradlew publish`. + +Use this to sanity-check that a change resolves correctly as a dependency before cutting an +actual release. + +## 4. Cut the release + +1. Create a GitHub release (tag + release notes) from `main` in the csec-java-agent repo. +2. Publishing the release (`release: published`) triggers `publish-release-to-maven.yml`, which + calls `publish-to-maven.yml` with `is-release=true`, `csec-run-unittest=false`, + `csec-run-instrumentation-verify=false` (these already passed pre-merge/on `main`, so the + release run skips re-running them). +## 5. Post-release verification + +- [ ] Confirm the Central Sonatype upload step in `publish-release-to-maven.yml` returned 200 - + visit https://central.sonatype.com/publishing/deployments to see the artifacts land. +- [ ] A silent Sonatype/GPG auth failure is the most likely release-day surprise - if the publish + step succeeded but the upload step failed, the artifacts are staged but not released; you + can re-run just the upload once credentials are fixed. +- [ ] Verify the Slack notification's `security-version`/`apm-version` match what you intended to + release. +- [ ] From K2io repo `newrelic-java-agent` bump the CSEC Version, raise a PR on newrelic's repo `newrelic-java-agent` +## Required secrets + +| Secret | Used for | +|---|---| +| `SONATYPE_USERNAME` / `SONATYPE_PASSWORD` | Maven Central / Sonatype auth (publish + staging upload) | +| `SIGNING_KEY` / `SIGNING_KEY_ID` / `SIGNING_KEY_PASSWORD` | GPG-signing published artifacts | +| `APM_AWS_ACCESS_KEY_ID` / `APM_AWS_SECRET_ACCESS_KEY` | Pulling the proprietary instrumentation jar zip from S3 during setup | + +## References + +- `.github/workflows/dependency-submission.yml` +- `.github/workflows/verify-instrumentation.yml`, `X-Reusable-VerifyInstrumentation.yml`, `verify-instrumentation-single.yml` +- `.github/workflows/publish-main-snapshot-to-maven.yml` +- `.github/workflows/publish-release-to-maven.yml` +- `.github/workflows/publish-to-maven.yml` +- `.github/workflows/build-integrated-jar.yml` +- `.github/workflows/X-Reusable-Build-Security-Agent.yml` +- `.github/actions/unit-test/action.yml`, `setup-environment/action.yml`, `publish-csec-local/action.yml` +- `Changelog.md`, `gradle.properties` +- [LOCAL_DEVELOPMENT.md](LOCAL_DEVELOPMENT.md) - building and running the agent locally