diff --git a/.github/workflows/checkmarx-one-scan.yml b/.github/workflows/checkmarx-one-scan.yml index 0c441b73..b79dea3a 100644 --- a/.github/workflows/checkmarx-one-scan.yml +++ b/.github/workflows/checkmarx-one-scan.yml @@ -8,6 +8,10 @@ on: schedule: - cron: "00 7 * * *" # Every day at 07:00 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: contents: read @@ -20,6 +24,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false - name: Checkmarx One CLI Action uses: checkmarx/ast-github-action@ef93013c95adc60160bc22060875e90800d3ecfc #v.2.3.19 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1f15117..6cac29e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,11 +2,15 @@ name: AST Java Wrapper CI on: [ pull_request ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: contents: read jobs: - integration-tests: + integration-tests: # zizmor: ignore[anonymous-definition] permissions: contents: read runs-on: cx-public-ubuntu-x64 @@ -16,6 +20,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} lfs: true + persist-credentials: false - name: Install Git LFS run: | @@ -34,7 +39,28 @@ jobs: - name: Configure echo mirror for dependency resolution run: | - sed -i 's||echocentralhttps://maven.echohq.com|' ~/.m2/settings.xml + mkdir -p ~/.m2 + cat > ~/.m2/settings.xml << EOF + + + + + echo-repo + * + https://maven.echohq.com + + + + + echo-repo + + ${ECHO_LIBRARIES_ACCESS_KEY} + + + + EOF + env: + ECHO_LIBRARIES_ACCESS_KEY: ${{ secrets.ECHO_LIBRARIES_ACCESS_KEY }} - name: Check existence of cx-linux binary run: | diff --git a/.github/workflows/manual-tag.yml b/.github/workflows/manual-tag.yml index 57f0d508..aad5bf3f 100644 --- a/.github/workflows/manual-tag.yml +++ b/.github/workflows/manual-tag.yml @@ -7,11 +7,16 @@ on: description: 'Next release tag' required: true +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + permissions: contents: read jobs: tag-creation: + name: Tag Creation permissions: contents: write # for Git to git push runs-on: cx-public-ubuntu-x64 @@ -19,17 +24,20 @@ jobs: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: - token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Tag env: INPUT_TAG: ${{ github.event.inputs.tag }} PR_NUMBER: ${{ github.event.pull_request.number }} PR_TITLE: ${{ github.event.pull_request.title }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} run: | echo "$INPUT_TAG" echo "NEXT_VERSION=$INPUT_TAG" >> $GITHUB_ENV message="$INPUT_TAG: PR #$PR_NUMBER $PR_TITLE" git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${REPO}" git tag -a "$INPUT_TAG" -m "$message" git push origin "$INPUT_TAG" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5a8b2c9f..40033e07 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -6,20 +6,26 @@ on: # branches: # - main +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + permissions: contents: read jobs: delete_tag: + name: Delete Tag permissions: - contents: write + contents: write # for gh release delete to remove tags and releases runs-on: cx-public-ubuntu-x64 steps: - name: Delete release and tag env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} run: | - gh release delete "1.0.0-SNAPSHOT" --yes --cleanup-tag --repo ${{ github.repository }} || true + gh release delete "1.0.0-SNAPSHOT" --yes --cleanup-tag --repo "${GH_REPO}" || true nightly: needs: delete_tag diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 81520b37..797fc193 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,15 +50,22 @@ on: required: true OSSRH_USERNAME: required: true + ECHO_LIBRARIES_ACCESS_KEY: + required: true + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false permissions: contents: read jobs: release: + name: Release permissions: - id-token: write - contents: write + id-token: write # for Maven Central publishing via OIDC + contents: write # for git push tag and creating GitHub release runs-on: cx-public-ubuntu-x64 outputs: CLI_VERSION: ${{ steps.extract_cli_version.outputs.CLI_VERSION }} @@ -67,8 +74,8 @@ jobs: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: - token: ${{ secrets.GITHUB_TOKEN }} lfs: true + persist-credentials: false - name: Download CLI if: inputs.cliTag @@ -105,11 +112,14 @@ jobs: id: set_tag_name env: INPUT_TAG: ${{ inputs.tag }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} run: | echo "$INPUT_TAG" echo "RELEASE_VERSION=$INPUT_TAG" >> $GITHUB_ENV git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${REPO}" git tag -a "$INPUT_TAG" -m "$INPUT_TAG" git push origin "$INPUT_TAG" echo "TAG_NAME=$INPUT_TAG" >> $GITHUB_OUTPUT @@ -127,7 +137,10 @@ jobs: - name: Configure echo mirror for dependency resolution run: | - sed -i 's||echocentralhttps://maven.echohq.com|' ~/.m2/settings.xml + sed -i 's||echo-repo'"$ECHO_LIBRARIES_ACCESS_KEY"'|' ~/.m2/settings.xml + sed -i 's||echo-repo*https://maven.echohq.com|' ~/.m2/settings.xml + env: + ECHO_LIBRARIES_ACCESS_KEY: ${{ secrets.ECHO_LIBRARIES_ACCESS_KEY }} - name: Update the POM version. run: mvn -B versions:set -DnewVersion="$RELEASE_VERSION" --file pom.xml -DskipTests diff --git a/.github/workflows/scan-github-action.yml b/.github/workflows/scan-github-action.yml new file mode 100644 index 00000000..12731513 --- /dev/null +++ b/.github/workflows/scan-github-action.yml @@ -0,0 +1,31 @@ +name: Scan for GitHub Actions issues + +on: + pull_request: + workflow_call: + +concurrency: + group: ${{ github.workflow }}-${{ github.repository }}-${{ github.ref }} + +permissions: {} + +jobs: + zizmor: + name: Scan repository contents + runs-on: cx-public-ubuntu-x64 + permissions: + contents: read + steps: + - name: Check out repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Run Zizmor linter + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + advanced-security: false + annotations: false + persona: pedantic + fail-on-no-inputs: false + online-audits: false diff --git a/.github/workflows/update-cli.yml b/.github/workflows/update-cli.yml index 64037254..1d42cf93 100644 --- a/.github/workflows/update-cli.yml +++ b/.github/workflows/update-cli.yml @@ -3,17 +3,23 @@ name: Update checkmarx ast cli on: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + permissions: contents: read jobs: update_cli: + name: Update CLI runs-on: cx-public-ubuntu-x64 steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: lfs: true + persist-credentials: false - name: Install Git LFS run: | diff --git a/.gitignore b/.gitignore index d6921c32..921e4fdf 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,5 @@ docker-compose.override.yml ################################# Thumbs.db .directory -.DS_Store \ No newline at end of file +.DS_Store +/.vscode diff --git a/Claude.md b/Claude.md new file mode 100644 index 00000000..c0c3be08 --- /dev/null +++ b/Claude.md @@ -0,0 +1,598 @@ +# Cloud.md - AST CLI Java Wrapper Repository + +## Project Overview + +The **ast-cli-java-wrapper** is a Java SDK/wrapper library that provides a shared infrastructure and abstraction layer for the Checkmarx Application Security Testing (AST) platform. It serves as a client library for integrating AST capabilities into Java-based applications and CI/CD pipelines. The wrapper offers technology-neutral repository interfaces and a metadata model for persisting Java classes, enabling developers to interact with the AST platform programmatically. + +**Repository:** https://github.com/CheckmarxDev/ast-cli-java-wrapper +**Package:** Published as Maven dependency (com.checkmarx.ast:ast-cli-java-wrapper) + +--- + +## Architecture + +The ast-cli-java-wrapper follows a modular architecture with clear separation of concerns: + +``` +ast-cli-java-wrapper/ +├── src/main/java/com/checkmarx/ast/ +│ ├── wrapper/ # Core wrapper utilities (CxConfig, CxException, CxConstants) +│ ├── asca/ # ASCA (Application Source Code Analysis) module +│ ├── codebashing/ # CodeBashing integration +│ ├── containersrealtime/ # Container scanning real-time results +│ ├── iacrealtime/ # IaC (Infrastructure as Code) real-time results +│ ├── kicsRealtimeResults/ # KICS (Kics Infrastructure Code Scanner) results +│ ├── ossrealtime/ # OSS (Open Source Software) real-time vulnerability scanning +│ ├── learnMore/ # Learning resources integration +│ ├── mask/ # Secret masking functionality +│ ├── project/ # Project management interfaces +│ ├── scan/ # Scan management +│ ├── results/ # Result handling and processing +│ ├── remediation/ # Remediation guidance +│ ├── predicate/ # Predicate-based filtering +│ └── tenant/ # Tenant management +├── src/test/java/ # Unit tests (JUnit 5) +└── src/main/resources/ # Configuration resources +``` + +**Design Pattern:** The wrapper uses a layered architecture with: +- **Interface Layer:** Technology-neutral interfaces for extensibility +- **Implementation Layer:** Concrete implementations for AST integration +- **Data Model Layer:** POJOs (Plain Old Java Objects) for data persistence and serialization +- **Utility Layer:** Configuration management (CxConfig), exception handling (CxException), and constants + +--- + +## Repository Structure + +``` +. +├── pom.xml # Maven configuration and dependencies +├── README.md # User-facing documentation +├── Cloud.md # This file - development/deployment documentation +├── src/ +│ ├── main/ +│ │ ├── java/ # Production source code +│ │ └── resources/ # Configuration files and resources +│ └── test/ +│ ├── java/ # Unit tests (JUnit 5 + Jupiter) +│ └── resources/ # Test configuration and fixtures +├── target/ # Build output (generated during maven clean install) +└── .github/ # GitHub Actions, workflows (if present) +``` + +**Key Files:** +- `pom.xml` - Defines Maven build configuration, dependencies, and JaCoCo code coverage plugin +- `src/main/java/com/checkmarx/ast/wrapper/CxConfig.java` - Core configuration class +- `src/main/java/com/checkmarx/ast/wrapper/CxException.java` - Custom exception handling +- `src/main/java/com/checkmarx/ast/wrapper/CxConstants.java` - Application constants + +--- + +## Technology Stack + +| Component | Technology | Version | +|-----------|-----------|---------| +| **Language** | Java | 8+ | +| **Build Tool** | Maven | 3+ | +| **JSON Processing** | Jackson | 2.21.1 | +| **JSON Serialization** | GSON | 2.12.1 | +| **Utilities** | Lombok | 1.18.32 | +| **Commons** | Apache Commons Lang3 | 3.18.0 | +| **JSON Parsing** | JSON-Simple | 1.1.1 | +| **Logging** | SLF4J | 2.0.12 | +| **Testing** | JUnit 5 (Jupiter) | 5.10.2 | +| **Code Coverage** | JaCoCo | 0.8.8 | + +**Key Dependencies:** +- **Jackson** - Primary JSON serialization/deserialization framework +- **GSON** - Alternative/supplementary JSON processing +- **Lombok** - Reduces boilerplate via annotations (@Data, @Getter, @Setter, etc.) +- **SLF4J** - Logging abstraction layer with slf4j-simple binding +- **JUnit 5** - Modern testing framework with parameterized tests and extensions + +--- + +## Development Setup + +### Prerequisites + +- **Java Development Kit (JDK):** Version 8 or higher + - Download from [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) or use OpenJDK + - Verify: `java -version` and `javac -version` + +- **Maven:** Version 3.6.0 or higher + - Download from [Apache Maven](https://maven.apache.org/download.cgi) + - Verify: `mvn -version` + +- **Git:** For cloning and version control + +### Local Setup Steps + +1. **Clone the repository:** + ```bash + git clone https://github.com/CheckmarxDev/ast-cli-java-wrapper.git + cd ast-cli-java-wrapper + ``` + +2. **Build the project:** + ```bash + mvn clean install + ``` + - Compiles source code, runs tests, and generates JAR artifact + - Output: `target/ast-cli-java-wrapper-[version].jar` + +3. **Run tests:** + ```bash + mvn test + ``` + +4. **Generate code coverage report:** + ```bash + mvn test jacoco:report + ``` + - Coverage report available at: `target/site/jacoco/index.html` + +5. **Install to local Maven repository:** + ```bash + mvn install + ``` + +### Integration Tests Setup + +To run integration tests that interact with the AST platform, set environment variables: + +**Linux/macOS:** +```bash +export CX_CLIENT_ID="your_client_id" +export CX_CLIENT_SECRET="your_client_secret" +export CX_APIKEY="your_api_key" +export CX_BASE_URI="https://ast.checkmarx.net" +export CX_BASE_AUTH_URI="https://iam.checkmarx.net" +export CX_TENANT="your_tenant_name" +export PATH_TO_EXECUTABLE="/path/to/ast-cli-executable" +``` + +**Windows (PowerShell):** +```powershell +setx CX_CLIENT_ID "your_client_id" +setx CX_CLIENT_SECRET "your_client_secret" +setx CX_APIKEY "your_api_key" +setx CX_BASE_URI "https://ast.checkmarx.net" +setx CX_BASE_AUTH_URI "https://iam.checkmarx.net" +setx CX_TENANT "your_tenant_name" +setx PATH_TO_EXECUTABLE "path\to\ast-cli-executable" +``` + +### IDE Configuration + +- **IntelliJ IDEA:** Import project as Maven project, mark `src/main/java` as Sources Root, `src/test/java` as Tests Root +- **Eclipse:** Use `mvn eclipse:eclipse` or import via "Existing Maven Projects" +- **VS Code:** Install "Extension Pack for Java" and "Maven for Java" extensions + +--- + +## Coding Standards + +### Code Style Guidelines + +1. **Naming Conventions:** + - Classes: PascalCase (e.g., `CxConfig`, `ScanResult`) + - Methods/Variables: camelCase (e.g., `getScanId()`, `scanDetails`) + - Constants: UPPER_SNAKE_CASE (e.g., `MAX_TIMEOUT`, `DEFAULT_PORT`) + - Private fields: prefix with underscore or use Lombok annotations + +2. **Lombok Annotations:** + - Use `@Data` for POJOs (generates getters, setters, equals, hashCode, toString) + - Use `@Getter` / `@Setter` for selective generation + - Use `@AllArgsConstructor` / `@NoArgsConstructor` for constructors + - Avoid verbose getter/setter implementations + +3. **Jackson Annotations:** + - Use `@JsonProperty("fieldName")` for JSON serialization mapping + - Use `@JsonIgnore` for excluding fields from JSON + - Use `@JsonDeserialize` / `@JsonSerialize` for custom type handling + +4. **Documentation:** + - Add JavaDoc comments for public classes and methods + - Keep comments concise and explain the "why", not the "what" + - Include examples in JavaDoc for complex methods + +5. **Exception Handling:** + - Extend `CxException` for domain-specific exceptions + - Use try-catch only for exceptional conditions, not control flow + - Log exceptions with appropriate level (error, warn, debug) + +6. **Code Organization:** + - Keep classes focused on a single responsibility + - Group related methods and fields together + - Use access modifiers appropriately (private by default, public only when needed) + +### Code Quality Tools + +- **JaCoCo Code Coverage:** Minimum coverage target is maintained via `pom.xml` configuration + - Excluded packages (data models, generated code) specified in JaCoCo excludes + - Run: `mvn jacoco:report` to generate coverage report + +- **Maven Compiler:** Configured for Java 8 compatibility + - Source: Java 8 + - Target: Java 8 + - Encoding: UTF-8 + +--- + +## Project Rules + +1. **Branching Strategy:** + - Main development branch: `main` + - Feature branches: `feature/*` + - Bug fixes: `bugfix/*` + - Hotfixes: `hotfix/*` + - Delete merged branches to keep repository clean + +2. **Commit Standards:** + - Write clear, descriptive commit messages + - Reference Jira ticket IDs in commit messages (e.g., "AST-12345: Add feature description") + - Keep commits atomic and logically grouped + +3. **Pull Requests:** + - Create PR against `main` branch + - Include description and acceptance criteria + - Ensure all tests pass before merging + - Require code review from at least one team member + - Squash commits on merge for cleaner history + +4. **Version Management:** + - Versions defined in `pom.xml` as `${ast.wrapper.version}` + - Follow semantic versioning (MAJOR.MINOR.PATCH) + - Update version before release + - Tag releases in Git (e.g., `v1.0.14`) + +5. **Dependency Management:** + - Keep dependencies updated, especially security patches + - Use Maven Dependabot or similar tools for automatic updates + - Review dependency changes in PRs for breaking changes + - Exclude conflicting transitive dependencies if needed + +6. **Documentation:** + - Keep README.md and Cloud.md synchronized with changes + - Document API changes in PR descriptions + - Update environment variables list if new ones are required + +--- + +## Testing Strategy + +### Testing Pyramid + +``` + /\ + / \ Integration Tests (Integration with AST platform) + /____\ + / \ + / \ Unit Tests (JUnit 5 - ~80% of tests) + /________\ + / \ + / \ Manual Testing & E2E + /____________\ +``` + +### Unit Testing + +- **Framework:** JUnit 5 (Jupiter) +- **Location:** `src/test/java/` +- **Naming Convention:** `*Test.java` or `*Tests.java` +- **Coverage Target:** >70% for core modules +- **Execution:** `mvn test` + +**Example Unit Test Structure:** +```java +@DisplayName("ScanResult Tests") +class ScanResultTest { + @Test + @DisplayName("Should deserialize scan result from JSON") + void testDeserializeScanResult() { + // Test implementation + } +} +``` + +### Integration Tests + +- **Environment Setup:** Requires AST platform credentials (see Development Setup) +- **Credentials:** Use environment variables for sensitive data +- **Isolation:** Test data should be isolated and cleaned up after tests +- **Skip in CI:** Can be skipped in pull request CI if platform access is limited + +### Test Fixtures & Mocks + +- Use JSON files in `src/test/resources/` for sample data +- Mock external dependencies where appropriate +- Use parameterized tests (`@ParameterizedTest`) for multiple scenarios + +### Code Coverage + +- **Tool:** JaCoCo Maven Plugin +- **Report Location:** `target/site/jacoco/index.html` +- **Excluded from Coverage:** Data models, POJOs, generated code (as specified in pom.xml) +- **Run:** `mvn test jacoco:report` + +--- + +## Known Issues + +1. **Java 8 Compatibility:** The project targets Java 8 for compatibility with older systems, which limits access to newer Java features (records, text blocks, sealed classes, etc.) + +2. **Dual JSON Libraries:** Both Jackson and GSON are included as dependencies, which may lead to subtle differences in serialization behavior. Prefer Jackson for primary serialization unless GSON is specifically required. + +3. **SLF4J Simple Binding:** The `slf4j-simple` binding is basic and may not be suitable for production environments. Consider switching to Logback or Log4j2 for advanced features. + +4. **JaCoCo Excludes:** Large portions of the codebase are excluded from code coverage (data models, results, etc.), which may mask untested code paths. Review excludes periodically. + +5. **Maven Build Performance:** Large transitive dependency trees and full coverage analysis can slow down builds. Use `mvn clean install -DskipTests` for faster builds during development. + +--- + +## Database Schema + +Not applicable - this is a client library with no persistent storage or database dependencies. + +--- + +## External Integrations + +1. **Checkmarx AST Platform:** + - **Purpose:** Provides security scanning, remediation guidance, and vulnerability data + - **Integration Points:** REST API calls via HTTP clients + - **Authentication:** OAuth 2.0 via `CX_CLIENT_ID` and `CX_CLIENT_SECRET`, or API key via `CX_APIKEY` + - **Endpoints:** Configured via `CX_BASE_URI` and `CX_BASE_AUTH_URI` + +2. **Maven Central Repository:** + - **Artifact:** com.checkmarx.ast:ast-cli-java-wrapper + - **Distribution:** Published JAR for inclusion in other projects + +3. **GitHub:** + - **Repository:** CheckmarxDev/ast-cli-java-wrapper + - **CI/CD:** Likely uses GitHub Actions for automated builds and tests + +--- + +## Deployment Info + +### Publishing to Maven Central + +1. **Build Release:** + ```bash + mvn clean install + ``` + +2. **Create Release Tag:** + ```bash + git tag -a v1.0.14 -m "Release version 1.0.14" + git push origin v1.0.14 + ``` + +3. **Deploy to Maven Central (Checkmarx Process):** + - Typically handled by CI/CD pipeline or release manager + - Requires Sonatype credentials and GPG signing + - Uses `mvn deploy` with Maven settings.xml configuration + +### Artifact Coordinates + +```xml + + com.checkmarx.ast + ast-cli-java-wrapper + 1.0.14 + +``` + +### Versioning + +- Current version: Check `pom.xml` for `` property +- Increment version before release +- Use semantic versioning (MAJOR.MINOR.PATCH) + +--- + +## Performance Considerations + +1. **Serialization:** Jackson is the primary JSON serialization engine and is optimized for performance. Ensure large result sets are streamed rather than loaded entirely in memory. + +2. **HTTP Client Configuration:** Consider connection pooling and timeout configurations when making requests to the AST platform. + +3. **Memory Usage:** For large scan results (KICS, OSS, containers), implement pagination or streaming to avoid OutOfMemoryError. + +4. **Compilation:** Java 8 target ensures compatibility but limits optimization opportunities available in newer Java versions. + +5. **Build Optimization:** Use `mvn clean install -T 1C` for parallel build threads to speed up compilation. + +--- + +## API/Endpoints/Interfaces + +### Core Interfaces + +**CxConfig** - Configuration management +- `getClientId()` - OAuth client identifier +- `getClientSecret()` - OAuth client secret +- `getApiKey()` - API key for authentication +- `getBaseUri()` - AST platform base URL +- `getBaseAuthUri()` - Identity/authentication service URL +- `getTenant()` - Tenant identifier + +**CxException** - Custom exception for domain errors +- Extends RuntimeException +- Used for all AST-specific error conditions + +### Module-Specific Interfaces + +- **Scan Module:** Scan creation, retrieval, status management +- **Results Module:** Result parsing, filtering, and analysis +- **ASCA Module:** Application source code analysis results +- **OSS Module:** Open source software vulnerability data +- **KICS Module:** Infrastructure as code scanning results +- **Remediation Module:** Remediation guidance and solutions +- **CodeBashing Module:** Security training integration +- **Containers Module:** Container image scanning results + +--- + +## Security & Access + +### Authentication + +1. **OAuth 2.0:** + - Client ID: `CX_CLIENT_ID` + - Client Secret: `CX_CLIENT_SECRET` + - Token endpoint: `CX_BASE_AUTH_URI` + - Recommended for service-to-service integration + +2. **API Key:** + - API Key: `CX_APIKEY` + - Recommended for personal use and testing + - Less secure than OAuth, use with caution in production + +### Authorization + +- **Tenant-Based:** Access controlled at tenant level via `CX_TENANT` +- **Scope-Based:** Different operations may require different permissions in AST platform +- **Role-Based:** User roles in AST platform determine available operations + +### Secrets Management + +- **Never commit credentials** to version control +- Use environment variables for local development +- Use CI/CD secrets managers for automated deployments +- Rotate API keys and client secrets regularly +- Audit access logs for suspicious activity + +### Data Protection + +- Use HTTPS for all API communication +- Jackson's default serialization is safe from injection attacks +- Validate all external input before processing +- Sanitize output if displaying user data +- Review JaCoCo excludes to ensure security code is tested + +--- + +## Logging + +### Logging Framework + +- **Framework:** SLF4J with slf4j-simple binding +- **Configuration:** Can be customized via `simplelogger.properties` in classpath +- **Production Use:** Consider upgrading to Logback or Log4j2 for advanced features + +### Logger Usage + +```java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class MyClass { + private static final Logger log = LoggerFactory.getLogger(MyClass.class); + + public void myMethod() { + log.info("Operation started"); + log.debug("Debug information"); + log.warn("Warning message"); + log.error("Error occurred", exception); + } +} +``` + +### Log Levels + +- **DEBUG:** Detailed information for debugging +- **INFO:** General informational messages +- **WARN:** Warning messages for potentially problematic situations +- **ERROR:** Error messages for failures + +### Sensitive Data + +- Never log credentials, API keys, or secrets +- Mask sensitive information in logs (user IDs, tokens, etc.) +- Use `log.debug()` for development-only logging +- Review logs regularly for security issues + +--- + +## Debugging Steps + +### Local Debugging + +1. **Enable Debug Logging:** + ```bash + mvn test -Dorg.slf4j.simpleLogger.defaultLogLevel=debug + ``` + +2. **IDE Debugging:** + - Set breakpoints in IDE + - Run tests in debug mode: Right-click test → "Debug" + - Use IntelliJ Debugger or Eclipse Debug perspective + +3. **Maven Debug Output:** + ```bash + mvn -X clean install # Very verbose output + mvn -e test # Print stack traces + ``` + +### Common Issues + +| Issue | Cause | Solution | +|-------|-------|----------| +| Test failures | Missing environment variables | Set CX_* environment variables for integration tests | +| Build failures | Java version mismatch | Ensure JDK 8+ is installed and JAVA_HOME is set | +| Dependency conflicts | Transitive dependency issues | Check pom.xml for exclusions or use `mvn dependency:tree` | +| OOM errors | Large scan results | Increase heap size: `export MAVEN_OPTS="-Xmx2g"` | +| Slow builds | Parallel testing disabled | Use `mvn clean install -T 1C` for parallel builds | + +### Useful Maven Commands + +```bash +mvn dependency:tree # Show dependency hierarchy +mvn help:describe-mojo -Dplugin=org.apache.maven.plugins:maven-compiler-plugin # Plugin help +mvn clean install -o # Offline build (use cached dependencies) +mvn test -Dtest=ScanResultTest # Run specific test +mvn test -Dtest=*Integration # Run tests matching pattern +``` + +### Profiling & Analysis + +```bash +# Generate detailed build report +mvn clean install -Dmaven.compiler.verbose=true + +# Check for deprecated API usage +mvn compile -Werror:sunapi + +# Analyze code with SpotBugs (if configured) +mvn spotbugs:check +``` + +--- + +## Contributing + +- Follow coding standards outlined above +- Write unit tests for new functionality +- Ensure all tests pass: `mvn clean install` +- Update documentation for API changes +- Create pull request with clear description +- Respond to code review feedback +- Maintain backward compatibility where possible + +--- + +## Support & Contact + +**Team:** Checkmarx - AST Integrations Team +**Project Link:** https://github.com/CheckmarxDev/ast-cli-java-wrapper +**Issues:** GitHub Issues for bug reports and feature requests + +--- + +**Last Updated:** April 20, 2026 +**Status:** In Active Development diff --git a/checkmarx-ast-cli.version b/checkmarx-ast-cli.version index fae17394..c5324251 100644 --- a/checkmarx-ast-cli.version +++ b/checkmarx-ast-cli.version @@ -1 +1 @@ -2.3.54 +2.3.57 diff --git a/pom.xml b/pom.xml index a468a86c..fdfeca80 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ com.fasterxml.jackson.core jackson-databind - 2.21.1 + 2.22.0 org.projectlombok @@ -211,14 +211,32 @@ + + + echo-repo + https://maven.echohq.com + + - central - https://central.sonatype.com/api/v1/publish + echo-repo + https://maven.echohq.com + + + echo-repo + https://maven.echohq.com + + true + + + false + + + diff --git a/src/main/resources/cx-linux b/src/main/resources/cx-linux index 85f008ed..9b4adbb5 100755 --- a/src/main/resources/cx-linux +++ b/src/main/resources/cx-linux @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:776d9864c0104e1d0023641ef931bd1c58478cf56768ce77f2bfbfd6e9e64493 -size 80568482 +oid sha256:2adc258dd3754f62456970a2c3b3e6f9127dbeede3df373079b2a24ca3e5f28c +size 83243170 diff --git a/src/main/resources/cx-linux-arm b/src/main/resources/cx-linux-arm index 10629171..8867d68e 100755 --- a/src/main/resources/cx-linux-arm +++ b/src/main/resources/cx-linux-arm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d40b3cfb9f930e96a9d6b494d4c7b9cd98e3bb857e55a0f55c92d764bb8c3c1a -size 75235490 +oid sha256:3bbf6915f6c7740ad41422859ec8f984402884abffe3777727b1c047b490099d +size 77660322 diff --git a/src/main/resources/cx-mac b/src/main/resources/cx-mac index e137bc67..ac4fb358 100755 --- a/src/main/resources/cx-mac +++ b/src/main/resources/cx-mac @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df4a2d6b72936afa65df8730f0ee491f6d518286421063f50df2e48d3d5b56f9 -size 160422432 +oid sha256:8b0e2df928eb29718936480d2492431e051d7058b60754c3514c87da864e2267 +size 165800304 diff --git a/src/main/resources/cx.exe b/src/main/resources/cx.exe index f2f6b695..c18ff7fe 100644 --- a/src/main/resources/cx.exe +++ b/src/main/resources/cx.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7227ac9dd89f344c12629d367774a2428595b3daff0a2e710981d924f13dbf4 -size 82488128 +oid sha256:08691c1a33980ae863dd8990bdafca9e64622d450727251355118b851306bfae +size 85228864 diff --git a/src/test/java/com/checkmarx/ast/ContainersRealtimeResultsTest.java b/src/test/java/com/checkmarx/ast/ContainersRealtimeResultsTest.java index 6911e4af..d21246c3 100644 --- a/src/test/java/com/checkmarx/ast/ContainersRealtimeResultsTest.java +++ b/src/test/java/com/checkmarx/ast/ContainersRealtimeResultsTest.java @@ -8,8 +8,6 @@ import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.*; /** @@ -19,10 +17,6 @@ */ class ContainersRealtimeResultsTest extends BaseTest { - private boolean isCliConfigured() { - return Optional.ofNullable(getConfig().getPathToExecutable()).filter(s -> !s.isEmpty()).isPresent(); - } - /* ------------------------------------------------------ */ /* Integration tests for Container Realtime scanning */ /* ------------------------------------------------------ */ @@ -35,7 +29,6 @@ private boolean isCliConfigured() { @Test @DisplayName("Basic container scan on Dockerfile returns detected images") void basicContainerRealtimeScan() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String dockerfilePath = "src/test/resources/Dockerfile"; Assumptions.assumeTrue(Files.exists(Paths.get(dockerfilePath)), "Dockerfile not found - cannot test container scanning"); @@ -61,7 +54,6 @@ void basicContainerRealtimeScan() throws Exception { @Test @DisplayName("Container scan with ignore file works correctly") void containerRealtimeScanWithIgnoreFile() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String dockerfilePath = "src/test/resources/Dockerfile"; String ignoreFile = "src/test/resources/ignored-packages.json"; Assumptions.assumeTrue(Files.exists(Paths.get(dockerfilePath)) && Files.exists(Paths.get(ignoreFile)), @@ -88,7 +80,6 @@ void containerRealtimeScanWithIgnoreFile() throws Exception { @Test @DisplayName("Repeated container scans produce consistent results") void containerRealtimeScanConsistency() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String dockerfilePath = "src/test/resources/Dockerfile"; Assumptions.assumeTrue(Files.exists(Paths.get(dockerfilePath)), "Dockerfile not found - cannot test consistency"); @@ -114,7 +105,6 @@ void containerRealtimeScanConsistency() throws Exception { @Test @DisplayName("Container domain objects are properly mapped from scan results") void containerDomainObjectMapping() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String dockerfilePath = "src/test/resources/Dockerfile"; Assumptions.assumeTrue(Files.exists(Paths.get(dockerfilePath)), "Dockerfile not found - cannot test mapping"); @@ -147,7 +137,6 @@ void containerDomainObjectMapping() throws Exception { @Test @DisplayName("Container scan throws appropriate exception for non-existent file") void containerScanHandlesInvalidPath() { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); // Test with a non-existent file path String invalidPath = "src/test/resources/NonExistentDockerfile"; diff --git a/src/test/java/com/checkmarx/ast/OssRealtimeParsingTest.java b/src/test/java/com/checkmarx/ast/OssRealtimeParsingTest.java index 6ea0fea0..d09769ba 100644 --- a/src/test/java/com/checkmarx/ast/OssRealtimeParsingTest.java +++ b/src/test/java/com/checkmarx/ast/OssRealtimeParsingTest.java @@ -6,8 +6,6 @@ import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.*; /** @@ -17,10 +15,6 @@ */ class OssRealtimeParsingTest extends BaseTest { - private boolean isCliConfigured() { - return Optional.ofNullable(getConfig().getPathToExecutable()).filter(s -> !s.isEmpty()).isPresent(); - } - /** * Tests basic OSS realtime scan functionality on pom.xml. * Verifies that the scan returns a valid results object with detected Maven dependencies. @@ -28,7 +22,6 @@ private boolean isCliConfigured() { @Test @DisplayName("Basic OSS scan on pom.xml returns Maven dependencies") void basicOssRealtimeScan() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); OssRealtimeResults results = wrapper.ossRealtimeScan("pom.xml", ""); @@ -49,7 +42,6 @@ void basicOssRealtimeScan() throws Exception { @Test @DisplayName("OSS scan with ignore file filters packages correctly") void ossRealtimeScanWithIgnoreFile() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String ignoreFile = "src/test/resources/ignored-packages.json"; Assumptions.assumeTrue(Files.exists(Paths.get(ignoreFile)), "Ignore file not found - cannot test ignore functionality"); @@ -69,7 +61,6 @@ void ossRealtimeScanWithIgnoreFile() throws Exception { @Test @DisplayName("Display detected package names for diagnostic purposes") void diagnosticPackageNames() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); OssRealtimeResults results = wrapper.ossRealtimeScan("pom.xml", ""); assertFalse(results.getPackages().isEmpty(), "Should have packages for diagnostic"); @@ -91,7 +82,6 @@ void diagnosticPackageNames() throws Exception { @Test @DisplayName("Ignore file excludes detected packages correctly") void ignoreFileExcludesPackages() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String ignoreFile = "src/test/resources/ignored-packages.json"; Assumptions.assumeTrue(Files.exists(Paths.get(ignoreFile)), "Ignore file not found - cannot test ignore functionality"); @@ -125,7 +115,6 @@ void ignoreFileExcludesPackages() throws Exception { @Test @DisplayName("Repeated OSS scans produce consistent results") void ossRealtimeScanConsistency() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); OssRealtimeResults firstScan = wrapper.ossRealtimeScan("pom.xml", ""); OssRealtimeResults secondScan = wrapper.ossRealtimeScan("pom.xml", ""); @@ -141,7 +130,6 @@ void ossRealtimeScanConsistency() throws Exception { @Test @DisplayName("Package domain objects are properly mapped from scan results") void packageDomainObjectMapping() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); OssRealtimeResults results = wrapper.ossRealtimeScan("pom.xml", ""); assertFalse(results.getPackages().isEmpty(), "Should have packages to validate mapping"); diff --git a/src/test/java/com/checkmarx/ast/ScanTest.java b/src/test/java/com/checkmarx/ast/ScanTest.java index a414281e..f37e5bdf 100644 --- a/src/test/java/com/checkmarx/ast/ScanTest.java +++ b/src/test/java/com/checkmarx/ast/ScanTest.java @@ -5,7 +5,6 @@ import com.checkmarx.ast.kicsRealtimeResults.KicsRealtimeResults; import com.checkmarx.ast.ossrealtime.OssRealtimeResults; import com.checkmarx.ast.scan.Scan; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -109,8 +108,6 @@ void testKicsRealtimeScan() throws Exception { @Test void testOssRealtimeScanWithIgnoredFile() throws Exception { - Assumptions.assumeTrue(getConfig().getPathToExecutable() != null && !getConfig().getPathToExecutable().isEmpty(), "PATH_TO_EXECUTABLE not set"); - String source = "pom.xml"; String ignoreFile = "src/test/resources/ignored-packages.json"; diff --git a/src/test/java/com/checkmarx/ast/SecretsRealtimeResultsTest.java b/src/test/java/com/checkmarx/ast/SecretsRealtimeResultsTest.java index a662d0f1..e2b0ebeb 100644 --- a/src/test/java/com/checkmarx/ast/SecretsRealtimeResultsTest.java +++ b/src/test/java/com/checkmarx/ast/SecretsRealtimeResultsTest.java @@ -7,8 +7,6 @@ import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.*; /** @@ -18,10 +16,6 @@ */ class SecretsRealtimeResultsTest extends BaseTest { - private boolean isCliConfigured() { - return Optional.ofNullable(getConfig().getPathToExecutable()).filter(s -> !s.isEmpty()).isPresent(); - } - /* ------------------------------------------------------ */ /* Integration tests for Secrets Realtime scanning */ /* ------------------------------------------------------ */ @@ -34,7 +28,6 @@ private boolean isCliConfigured() { @Test @DisplayName("Basic secrets scan on python file returns detected secrets") void basicSecretsRealtimeScan() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String pythonFile = "src/test/resources/python-vul-file.py"; Assumptions.assumeTrue(Files.exists(Paths.get(pythonFile)), "Python vulnerable file not found - cannot test secrets scanning"); @@ -61,7 +54,6 @@ void basicSecretsRealtimeScan() throws Exception { @Test @DisplayName("Secrets scan with ignore file works correctly") void secretsRealtimeScanWithIgnoreFile() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String pythonFile = "src/test/resources/python-vul-file.py"; String ignoreFile = "src/test/resources/ignored-packages.json"; Assumptions.assumeTrue(Files.exists(Paths.get(pythonFile)) && Files.exists(Paths.get(ignoreFile)), @@ -86,7 +78,6 @@ void secretsRealtimeScanWithIgnoreFile() throws Exception { @Test @DisplayName("Repeated secrets scans produce consistent results") void secretsRealtimeScanConsistency() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String pythonFile = "src/test/resources/python-vul-file.py"; Assumptions.assumeTrue(Files.exists(Paths.get(pythonFile)), "Python file not found - cannot test consistency"); @@ -109,7 +100,6 @@ void secretsRealtimeScanConsistency() throws Exception { @Test @DisplayName("Secret domain objects are properly mapped from scan results") void secretDomainObjectMapping() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String pythonFile = "src/test/resources/python-vul-file.py"; Assumptions.assumeTrue(Files.exists(Paths.get(pythonFile)), "Python file not found - cannot test mapping"); @@ -141,7 +131,6 @@ void secretDomainObjectMapping() throws Exception { @Test @DisplayName("Secrets scan on clean file returns empty results") void secretsScanOnCleanFile() throws Exception { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String cleanFile = "src/test/resources/csharp-no-vul.cs"; Assumptions.assumeTrue(Files.exists(Paths.get(cleanFile)), "Clean C# file not found - cannot test clean scan"); @@ -161,7 +150,6 @@ void secretsScanOnCleanFile() throws Exception { @Test @DisplayName("Secrets scan throws appropriate exception for non-existent file") void secretsScanHandlesInvalidPath() { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); // Test with a non-existent file path String invalidPath = "src/test/resources/NonExistentFile.py"; @@ -186,7 +174,6 @@ void secretsScanHandlesInvalidPath() { @Test @DisplayName("Secrets scan handles multiple file types correctly") void secretsScanMultipleFileTypes() { - Assumptions.assumeTrue(isCliConfigured(), "PATH_TO_EXECUTABLE not configured - skipping integration test"); String[] testFiles = { "src/test/resources/python-vul-file.py",