diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..f4773f7e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,105 @@ +# Repository Guidelines + +## Project Purpose & Structure + +The **Sysdig Secure Jenkins Plugin** integrates Sysdig Secure image scanning into Jenkins pipelines and freestyle jobs. It enables automated security scans and policy evaluations for container images. + +### Module Organization +The codebase follows a **Hexagonal Architecture (Ports & Adapters)** to decouple the core domain from external dependencies (Jenkins, Sysdig API). + +- **`src/main/java/com/sysdig/jenkins/plugins/sysdig/`**: + - **`domain/`**: Core business logic (e.g., `ImageScanner`, `ScanResult`). Pure Java, no external dependencies. + - **`application/`**: Use cases and orchestration (e.g., `ImageScanningService`). + - **`infrastructure/`**: Implementations of ports (e.g., `jenkins/` for Jenkins integration, `scanner/` for Sysdig CLI). +- **`src/main/resources/`**: Jelly files for Jenkins UI (`index.jelly`) and other resources. +- **`src/test/java/`**: Unit and integration tests, mirroring the package structure. + +## Build, Test, & Development + +This project uses **Maven** for build management and optionally **Nix** for a consistent environment. + +### Key Commands + +- **Build Plugin**: `mvn clean package` (generates `target/sysdig-secure.hpi`). +- **Run Tests**: `mvn clean verify` (runs unit and integration tests). +- **Run Locally**: `mvn hpi:run` (starts a local Jenkins instance with the plugin installed). +- **Format Code**: `make format` (applies Spotless formatting). +- **Verify All**: `make verify` (runs formatting check + tests). +- **Dev Shell**: `nix develop` (enters a shell with Java/Maven pre-configured). + +## Coding Style & Naming + +- **Architecture**: Strictly adhere to Hexagonal Architecture. Do not leak Jenkins or Sysdig API dependencies into the `domain` package. +- **Formatting**: + - **Java**: 4 spaces indentation. + - **XML/JS**: 2 spaces indentation. + - Enforced via **Spotless**. Always run `make format` before committing. +- **Naming**: Use descriptive, standard Java naming conventions (CamelCase for classes, camelCase for methods/variables). + +## Testing Guidelines + +- **Frameworks**: JUnit, Mockito. +- **Coverage**: Aim for high coverage in `domain` logic. +- **Conventions**: + - Unit tests should mock external dependencies (ports). + - Integration tests (in `infrastructure/` or `e2e/`) verify interactions with Jenkins or real APIs. +- **Execution**: Run specific tests via Maven or all tests with `mvn clean verify`. + +## Commit & Pull Request Guidelines + +### Commit Messages +Follow **Conventional Commits**: +- Format: `(): ` +- Types: `feat`, `fix`, `refactor`, `chore`, `test`, `docs`. +- Examples: + - `feat(ui): add image diff table` + - `fix(scanner): respect accepted risks in policy evaluation` + - `refactor(domain): split policy rules` + +### Pull Requests +- Link relevant issues (e.g., "Fixes #149"). +- Include a summary of changes. +- For UI changes, attach screenshots. +- Ensure `make verify` passes locally. + +## Documentation Updates + +The agent must keep this file (`AGENTS.md`) and `README.md` updated as the project evolves. +- If a new build tool or key command is added, update this guide. +- Suggest documentation improvements to the user if existing docs are unclear or outdated. + +## Maintenance Guidelines + +This project includes a `Makefile` to simplify common maintenance tasks. **It is highly recommended to run `make update`** to perform a complete project update, as it orchestrates all maintenance tasks (Jenkins version, Parent POM, dependencies, etc.) in the correct order. + +### Updating Dependencies & Parent POM +Regularly update the parent POM and project dependencies to ensure security and compatibility. + +1. **Update Parent POM**: + Run `make update-parent-pom` (executes `mvn versions:update-parent`). + *Reference: [Update parent POM](https://www.jenkins.io/doc/developer/tutorial-improve/update-parent-pom/)* + +2. **Update Dependencies**: + Run `make update-dependencies` (executes `mvn versions:use-latest-versions`). + +3. **Update All (Recommended)**: + Run `make update` to update the parent POM, dependencies, flake, and the Sysdig CLI version in one go. + +### Updating Base Jenkins Version +**Important:** Update the base Jenkins version **before** updating the parent POM or other dependencies. + +1. **Run Automation**: + Run `make update-jenkins-version`. This command: + - Fetches the latest **unmaintained LTS version** from [endoflife.date](https://endoflife.date/jenkins). + - Calculates the corresponding baseline (e.g., `2.516`). + - Fetches the latest available **Bill of Materials (BOM)** version for that baseline. + - Updates `jenkins.baseline`, `jenkins.version`, and the BOM dependency in `pom.xml` automatically using `sed`. + +2. **Verify**: + Run `make verify` to ensure the plugin builds and tests pass with the new version. + +### Updating Sysdig CLI Version +To update the embedded Sysdig CLI version used by the scanner: + +1. Run `make update-sysdig-cli-version`. + This fetches the latest version from Sysdig and updates `RemoteSysdigImageScanner.java`. diff --git a/Makefile b/Makefile index b15fd26c..f5b83c93 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,18 @@ -update: update-parent-pom update-dependencies update-flake update-sysdig-cli-version +update: update-jenkins-version update-parent-pom update-dependencies update-flake update-sysdig-cli-version + +update-jenkins-version: + @echo "Fetching latest unmaintained LTS Jenkins version..." + @version=$$(curl -s https://endoflife.date/api/v1/products/jenkins/ | jq -r '.result.releases | map(select(.isMaintained == false)) | first | .latest.name') && \ + baseline=$$(echo $$version | cut -d. -f1-2) && \ + echo "Found Jenkins version: $$version (Baseline: $$baseline)" && \ + echo "Fetching latest BOM version for bom-$$baseline.x..." && \ + bom_version=$$(curl -s "https://repo.jenkins-ci.org/public/io/jenkins/tools/bom/bom-$$baseline.x/maven-metadata.xml" | grep -oPm1 "(?<=)[^<]+") && \ + echo "Found BOM version: $$bom_version" && \ + sed -i 's|.*|'$$baseline'|' pom.xml && \ + sed -i 's|.*|'$$version'|' pom.xml && \ + sed -i "/bom-\$${jenkins.baseline}.x<\/artifactId>/,+2 s|.*|$$bom_version|" pom.xml && \ + echo "Updated pom.xml to Jenkins $$version, Baseline $$baseline, BOM $$bom_version" update-parent-pom: mvn versions:update-parent -DgenerateBackupPoms=false diff --git a/flake.lock b/flake.lock index b799c7bc..a7d579d4 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1761440988, - "narHash": "sha256-2qsow3cQIgZB2g8Cy8cW+L9eXDHP6a1PsvOschk5y+E=", + "lastModified": 1767364772, + "narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "de69d2ba6c70e747320df9c096523b623d3a4c35", + "rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa", "type": "github" }, "original": { diff --git a/pom.xml b/pom.xml index e1b82303..33ff63e7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 5.27 + 6.2111.v8b_6a_1d599df3 @@ -41,8 +41,8 @@ - 2.479 - ${jenkins.baseline}.3 + 2.516 + 2.516.3 false 3.0 @@ -57,7 +57,7 @@ io.jenkins.tools.bom bom-${jenkins.baseline}.x - 5054.v620b_5d2b_d5e6 + 5857.vb_f3dd0731f44 pom import diff --git a/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/ScanResult.java b/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/ScanResult.java index 95685c0a..9f7af624 100644 --- a/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/ScanResult.java +++ b/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/ScanResult.java @@ -1,10 +1,10 @@ package com.sysdig.jenkins.plugins.sysdig.domain.vm.scanresult; import com.sysdig.jenkins.plugins.sysdig.domain.vm.scanresult.diff.ScanResultDiff; +import edu.umd.cs.findbugs.annotations.Nullable; import java.io.Serializable; import java.math.BigInteger; import java.util.*; -import javax.annotation.Nullable; public class ScanResult implements Serializable { private final EvaluationResult globalEvaluationResult; diff --git a/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/Vulnerability.java b/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/Vulnerability.java index b9d6c018..10a4fe11 100644 --- a/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/Vulnerability.java +++ b/src/main/java/com/sysdig/jenkins/plugins/sysdig/domain/vm/scanresult/Vulnerability.java @@ -1,10 +1,10 @@ package com.sysdig.jenkins.plugins.sysdig.domain.vm.scanresult; import com.sysdig.jenkins.plugins.sysdig.domain.AggregateChild; +import edu.umd.cs.findbugs.annotations.Nullable; import java.io.Serializable; import java.util.*; import java.util.stream.Collectors; -import javax.annotation.Nullable; public class Vulnerability implements AggregateChild, Serializable { private final String cve; diff --git a/src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/RemoteSysdigImageScanner.java b/src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/RemoteSysdigImageScanner.java index bfb5b261..f9eb27e3 100644 --- a/src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/RemoteSysdigImageScanner.java +++ b/src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/RemoteSysdigImageScanner.java @@ -32,7 +32,7 @@ import java.net.URL; public class RemoteSysdigImageScanner { - private static final String FIXED_SCANNED_VERSION = "1.23.0"; + private static final String FIXED_SCANNED_VERSION = "1.24.2"; private final ScannerPaths scannerPaths; private final String imageName; private final RetriableRemoteDownloader retriableRemoteDownloader; diff --git a/src/test/java/com/sysdig/jenkins/plugins/sysdig/application/ui/report/VulnerabilityReportProcessorTest.java b/src/test/java/com/sysdig/jenkins/plugins/sysdig/application/ui/report/VulnerabilityReportProcessorTest.java index 98507e81..75cbfe38 100644 --- a/src/test/java/com/sysdig/jenkins/plugins/sysdig/application/ui/report/VulnerabilityReportProcessorTest.java +++ b/src/test/java/com/sysdig/jenkins/plugins/sysdig/application/ui/report/VulnerabilityReportProcessorTest.java @@ -23,8 +23,7 @@ void testPolicyEvaluationSummaryIsGeneratedCorrectly() throws IOException { // Then // FIXME(fede): the "URL" part should be the rule description, currently it's empty in sysdig-cli-scanner // 1.22.3. I expect this will be fixed in newer versions. - JsonElement expectedJson = JsonParser.parseString( - """ + JsonElement expectedJson = JsonParser.parseString(""" { "columns":[ {"title":"Tag"}, diff --git a/src/test/java/com/sysdig/jenkins/plugins/sysdig/e2e/ImageScanningE2EPipelineTests.java b/src/test/java/com/sysdig/jenkins/plugins/sysdig/e2e/ImageScanningE2EPipelineTests.java index b798cff0..ef3aafbf 100644 --- a/src/test/java/com/sysdig/jenkins/plugins/sysdig/e2e/ImageScanningE2EPipelineTests.java +++ b/src/test/java/com/sysdig/jenkins/plugins/sysdig/e2e/ImageScanningE2EPipelineTests.java @@ -45,8 +45,7 @@ void testPipelineWithCredentialsAndAssertLogOutput() throws Exception { @Test void testPipelineWithAllConfigs() throws Exception { - var job = helpers.createPipelineJobWithScript( - """ + var job = helpers.createPipelineJobWithScript(""" sysdigImageScan engineCredentialsId: 'sysdig-secure', engineURL: 'https://custom-engine-url.com', engineVerify: false, @@ -56,8 +55,7 @@ void testPipelineWithAllConfigs() throws Exception { cliVersionToApply: 'custom', policiesToApply: 'custom-policy-name', bailOnFail: false, - bailOnPluginFail: false""") - .buildWithRemoteExecution(); + bailOnPluginFail: false""").buildWithRemoteExecution(); var build = jenkins.buildAndAssertSuccess(job); @@ -105,8 +103,7 @@ void testPipelineWithMinimalConfigButAlsoGlobalConfig() throws Exception { @Test void testPipelineWithImageToCompareConfig() throws Exception { - var job = helpers.createPipelineJobWithScript( - """ + var job = helpers.createPipelineJobWithScript(""" sysdigImageScan engineCredentialsId: 'sysdig-secure', engineURL: 'https://custom-engine-url.com', engineVerify: false, @@ -115,8 +112,7 @@ void testPipelineWithImageToCompareConfig() throws Exception { customCliVersion: '2.0.0', cliVersionToApply: 'custom', bailOnFail: false, - bailOnPluginFail: false""") - .buildWithRemoteExecution(); + bailOnPluginFail: false""").buildWithRemoteExecution(); var build = jenkins.buildAndAssertSuccess(job);