From cf1f632e607413d6e562c455a93364d99022b86a Mon Sep 17 00:00:00 2001 From: Yiftach Cohen Date: Wed, 21 Jan 2026 16:05:48 +0200 Subject: [PATCH] [PPSC-280] docs: add oss best practices and developer tooling Add comprehensive documentation for contributors including development setup, code style guidelines, and testing patterns. Introduce EditorConfig, pre-commit hooks, and YAML linting configuration to enforce consistency across the project. --- .editorconfig | 33 ++++ .github/CONTRIBUTING.md | 211 +++++++++++++++++++++- .github/ISSUE_TEMPLATE/bug_report.md | 14 +- .github/ISSUE_TEMPLATE/feature_request.md | 5 + .github/ISSUE_TEMPLATE/security_issue.md | 1 + .github/SECURITY.md | 5 +- .github/pull_request_template.md | 8 + .pre-commit-config.yaml | 56 ++++++ .yamllint.yml | 22 +++ README.md | 66 ++++++- docs/CHANGELOG.md | 3 +- docs/CI-SETUP.md | 12 ++ docs/CLAUDE.md | 6 + docs/DISTRIBUTION-SETUP.md | 18 +- docs/FEATURES.md | 11 +- docs/INSTALL-IMPROVEMENTS.md | 46 ++++- 16 files changed, 484 insertions(+), 33 deletions(-) create mode 100644 .editorconfig create mode 100644 .pre-commit-config.yaml create mode 100644 .yamllint.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c7c4279 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# EditorConfig helps maintain consistent coding styles across editors +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.go] +indent_style = tab + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.md] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = false + +[*.json] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab + +[*.sh] +indent_style = space +indent_size = 4 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a974d8c..1fee98e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,15 @@ # Contributing -Thanks for your interest in contributing! +Thanks for your interest in contributing to the Armis CLI! + +## Table of Contents + +- [Scope](#scope) +- [Development Setup](#development-setup) +- [Code Style](#code-style) +- [Testing](#testing) +- [Contribution Process](#contribution-process) +- [License](#license) ## Scope @@ -15,12 +24,204 @@ the Armis cloud APIs. Contributions should focus on: Security detection logic, analysis engines, and backend services are intentionally out of scope. +## Development Setup + +### Prerequisites + +- Go 1.24 or later +- [golangci-lint](https://golangci-lint.run/welcome/install/) v2.0+ +- Make + +### Getting Started + +```bash +# Clone the repository +git clone https://github.com/ArmisSecurity/armis-cli.git +cd armis-cli + +# Install dev tools (gotestsum for better test output) +make tools + +# Build the binary +make build + +# Run tests +make test + +# Run linters +make lint +``` + +### Available Make Targets + +| Target | Description | +|--------|-------------| +| `make build` | Build the binary to `bin/armis-cli` | +| `make test` | Run tests with gotestsum (or go test as fallback) | +| `make lint` | Run golangci-lint | +| `make install` | Install binary to `/usr/local/bin` | +| `make clean` | Remove build artifacts | +| `make tools` | Install development tools | +| `make scan` | Run security scan on this repository | + +## Code Style + +### Formatting + +- All code must be formatted with `gofmt` +- Use tabs for indentation (Go standard) +- Run `gofmt -w .` before committing or use editor integration + +### Linting + +We use [golangci-lint](https://golangci-lint.run/) with the following linters enabled: + +| Linter | Purpose | +|--------|---------| +| `errcheck` | Check for unchecked errors | +| `govet` | Report suspicious constructs | +| `ineffassign` | Detect ineffectual assignments | +| `staticcheck` | Advanced static analysis | +| `unused` | Find unused code | +| `gosec` | Security-focused linting | +| `goconst` | Find repeated strings that could be constants | +| `misspell` | Catch common spelling mistakes | + +Run `make lint` to check your code before submitting. + +### Error Handling + +- Always wrap errors with context using `fmt.Errorf("context: %w", err)` +- Provide actionable error messages for user-facing errors +- Don't ignore errors; use `_ = fn()` explicitly if intentional + +```go +// Good +if err != nil { + return fmt.Errorf("failed to read config: %w", err) +} + +// Bad +if err != nil { + return err // Missing context +} +``` + +### Comments + +- Add package-level comments to all packages +- Document exported functions and types +- Focus on "why" rather than "what" in inline comments + +## Testing + +### Running Tests + +```bash +# Run all tests +make test + +# Run with verbose output +go test -v ./... + +# Run specific package tests +go test -v ./internal/api/... + +# Run with race detection +go test -race ./... + +# Run with coverage +go test -coverprofile=coverage.out ./... +go tool cover -html=coverage.out +``` + +### Writing Tests + +- Use table-driven tests for multiple test cases +- Place tests in the same package as the code being tested +- Use meaningful test names that describe the scenario + +```go +func TestFormatBytes(t *testing.T) { + tests := []struct { + name string + bytes int64 + expected string + }{ + {"zero bytes", 0, "0B"}, + {"kilobytes", 1024, "1.0KiB"}, + {"megabytes", 1048576, "1.0MiB"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := formatBytes(tt.bytes) + if result != tt.expected { + t.Errorf("got %s, want %s", result, tt.expected) + } + }) + } +} +``` + +### Test Utilities + +- HTTP test helpers are available in `internal/testutil/` +- Sample test data is in `test/` directory + ## Contribution Process -1. Fork the repository -2. Create a feature branch -3. Add tests where applicable -4. Submit a pull request with a clear description +1. **Fork the repository** and clone it locally + +2. **Create a feature branch** from `main`: + + ```bash + git checkout -b feature/your-feature-name + ``` + +3. **Make your changes**: + - Keep commits focused and atomic + - Write clear commit messages + +4. **Run quality checks**: + + ```bash + make lint + make test + ``` + +5. **Submit a pull request**: + - Fill out the PR template completely + - Link related issues + - Ensure CI passes + +### Commit Messages + +Follow conventional commit style: + +```text +type: brief description + +Longer explanation if needed. + +Fixes #123 +``` + +Types: `feat`, `fix`, `docs`, `test`, `refactor`, `chore` + +### Pull Request Guidelines + +- Keep PRs focused on a single change +- Update documentation if behavior changes +- Add tests for new functionality +- Ensure all CI checks pass +- Respond to review feedback promptly + +## Reporting Issues + +- **Bugs**: Use the [bug report template](https://github.com/ArmisSecurity/armis-cli/issues/new?template=bug_report.md) +- **Features**: Use the [feature request template](https://github.com/ArmisSecurity/armis-cli/issues/new?template=feature_request.md) +- **Security**: See [SECURITY.md](./SECURITY.md) for vulnerability reporting ## License diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 419b318..266e113 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,28 +7,34 @@ assignees: '' --- ## Description + A clear and concise description of the bug. ## Steps to Reproduce -1. -2. -3. + +1. +2. +3. ## Expected Behavior + What you expected to happen. ## Actual Behavior + What actually happened. ## Environment + - OS: [e.g., Ubuntu 22.04, macOS 13.0, Windows 11] - armis-cli version: [e.g., v1.0.0] - Go version (if building from source): [e.g., 1.21.0] - Installation method: [binary, go install, docker, etc.] ## Additional Context + Add any other context, logs, or screenshots about the problem here. -``` +```text # Paste relevant logs or command output here ``` diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 2861949..89fd93e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,16 +7,21 @@ assignees: '' --- ## Problem Statement + A clear description of the problem this feature would solve. ## Proposed Solution + Describe your proposed solution or feature. ## Alternatives Considered + Describe any alternative solutions or features you've considered. ## Use Case + Describe how this feature would be used and who would benefit from it. ## Additional Context + Add any other context, mockups, or examples about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/security_issue.md b/.github/ISSUE_TEMPLATE/security_issue.md index 6ad2c50..02691ad 100644 --- a/.github/ISSUE_TEMPLATE/security_issue.md +++ b/.github/ISSUE_TEMPLATE/security_issue.md @@ -13,6 +13,7 @@ assignees: '' Please report security vulnerabilities by following the process in our [SECURITY.md](../../SECURITY.md) file. For responsible disclosure: + 1. Email security contact listed in SECURITY.md 2. Include detailed description and reproduction steps 3. Allow time for patch before public disclosure diff --git a/.github/SECURITY.md b/.github/SECURITY.md index ad556eb..f618a82 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -20,9 +20,10 @@ We take security issues seriously and appreciate responsible disclosure. If you believe you have identified a security vulnerability in this CLI, please report it **privately by email**. -**Email:** security@armis.com +**Email:** When reporting, please include: + - CLI version - Operating system and runtime environment - Clear steps to reproduce or a proof of concept @@ -102,4 +103,4 @@ Our vulnerability disclosure approach aligns with widely accepted responsible disclosure practices, including those described in the Armis Vulnerability Disclosure Policy: -https://www.armis.com/legal-compliance/vulnerability-disclosure-policy/ + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d472010..1c1e17c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,9 @@ ## Description + Brief description of the changes in this PR. ## Type of Change + - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) @@ -11,15 +13,19 @@ Brief description of the changes in this PR. - [ ] Test coverage improvement ## Related Issues + Fixes #(issue number) ## Testing + Describe the tests you ran and how to reproduce them: + - [ ] Unit tests pass locally - [ ] Integration tests pass (if applicable) - [ ] Manual testing performed ## Checklist + - [ ] My code follows the project's code style - [ ] I have performed a self-review of my code - [ ] I have commented my code where necessary @@ -30,7 +36,9 @@ Describe the tests you ran and how to reproduce them: - [ ] Any dependent changes have been merged and published ## Screenshots (if applicable) + Add screenshots to help explain your changes. ## Additional Notes + Any additional information that reviewers should know. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..61a66a7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,56 @@ +# Pre-commit hooks for armis-cli +# Install: pip install pre-commit && pre-commit install +# Run manually: pre-commit run --all-files +# https://pre-commit.com + +repos: + # General file checks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - id: end-of-file-fixer + - id: check-yaml + - id: check-json + - id: check-merge-conflict + - id: check-added-large-files + args: [--maxkb=1000] + + # Go formatting + - repo: https://github.com/dnephin/pre-commit-golang + rev: v0.5.1 + hooks: + - id: go-fmt + - id: go-vet + - id: go-mod-tidy + + # golangci-lint + - repo: https://github.com/golangci/golangci-lint + rev: v2.1.6 + hooks: + - id: golangci-lint + + # Markdown linting + # Disabled rules: MD013 (line-length) - too restrictive for docs with URLs/tables + # MD033 (inline-HTML) - needed for badges and advanced formatting + # MD041 (first-line-heading) - not all docs need H1 first + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.44.0 + hooks: + - id: markdownlint + args: [--fix, --disable, MD013, MD033, MD041, --] + + # Shell script linting + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.10.0.1 + hooks: + - id: shellcheck + args: [-x] + + # YAML linting + - repo: https://github.com/adrienverge/yamllint + rev: v1.37.0 + hooks: + - id: yamllint + args: [-c, .yamllint.yml] diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..ae4cd4d --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,22 @@ +# yamllint configuration +# https://yamllint.readthedocs.io + +extends: default + +rules: + line-length: + max: 120 + level: warning + truthy: + allowed-values: ["true", "false", "on", "off", "yes", "no"] + comments: + min-spaces-from-content: 1 + braces: + min-spaces-inside: 0 + max-spaces-inside: 0 + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + indentation: + spaces: 2 + indent-sequences: true diff --git a/README.md b/README.md index 345d40b..88db716 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ ![Armis Logo](https://github.com/ArmisSecurity/armis-cli/blob/main/docs/assets/logo-dark.svg) + # Armis CLI [![Build Status](https://github.com/ArmisSecurity/armis-cli/actions/workflows/release.yml/badge.svg)](https://github.com/ArmisSecurity/armis-cli/actions) @@ -14,6 +15,7 @@ Enterprise-grade CLI for static application security scanning with Armis Cloud. --- ## Table of Contents + - [Features](#features) - [Installation](#installation) - [Verification](#verification) @@ -36,17 +38,17 @@ Enterprise-grade CLI for static application security scanning with Armis Cloud. --- ## Features + - Scan repositories and container images - Multiple output formats: human, JSON, SARIF, JUnit XML - CI/CD ready: GitHub Actions, Jenkins, GitLab, Azure, Bitbucket, CircleCI - Configurable exit codes and fail-on severity - Secure authentication, size limits, and best practices - - ## Installation ### Homebrew (macOS/Linux) + **Prerequisites:** [Homebrew](https://brew.sh) must be installed first. ```bash @@ -54,37 +56,46 @@ brew install armissecurity/tap/armis-cli ``` ### Quick Install Script + **Linux/macOS:** + ```bash curl -sSL https://raw.githubusercontent.com/ArmisSecurity/armis-cli/main/scripts/install.sh | bash ``` The script will automatically: + - Install to `~/.local/bin` (no sudo required) or `/usr/local/bin` as fallback - Verify the installation - Check if the command is in your PATH **Windows (PowerShell):** + ```powershell irm https://raw.githubusercontent.com/ArmisSecurity/armis-cli/main/scripts/install.ps1 | iex ``` ### Scoop (Windows) + ```powershell scoop bucket add armis https://github.com/ArmisSecurity/scoop-bucket scoop install armis-cli ``` ### Manual Download + Download the latest release for your platform from the [releases page](https://github.com/ArmisSecurity/armis-cli/releases). ### Using Go + ```bash go install github.com/ArmisSecurity/armis-cli/cmd/armis-cli@latest ``` ### Verify Installation + After installation, verify that the CLI is working: + ```bash which armis-cli armis-cli --version @@ -95,6 +106,7 @@ armis-cli --version If you see "command not found" after installation: 1. **Check if it's installed:** + ```bash ls -la ~/.local/bin/armis-cli # or @@ -102,19 +114,22 @@ If you see "command not found" after installation: ``` 2. **Check your PATH:** + ```bash echo $PATH ``` 3. **Add to PATH if needed:** - + For **zsh** (default on macOS): + ```bash echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc source ~/.zshrc ``` - + For **bash**: + ```bash echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bash_profile source ~/.bash_profile @@ -123,6 +138,7 @@ If you see "command not found" after installation: 4. **Or open a new terminal window** and try again. 5. **Run directly with full path:** + ```bash ~/.local/bin/armis-cli --help ``` @@ -134,6 +150,7 @@ If you see "command not found" after installation: All releases include cryptographic signatures, SBOMs, and SLSA Level 3 provenance attestations for supply chain security. ### Verify Checksums (Cosign) + ```bash # Download the binary, checksums, and signature curl -LO https://github.com/ArmisSecurity/armis-cli/releases/latest/download/armis-cli-linux-amd64.tar.gz @@ -152,6 +169,7 @@ sha256sum --ignore-missing -c armis-cli-checksums.txt ``` ### Verify SLSA Provenance (Supply Chain Security) + ```bash # Install slsa-verifier go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest @@ -167,6 +185,7 @@ slsa-verifier verify-artifact \ ``` ### Inspect SBOM (Software Bill of Materials) + ```bash # Download SBOM (CycloneDX JSON format) curl -LO https://github.com/ArmisSecurity/armis-cli/releases/latest/download/armis-cli-linux-amd64.tar.gz.sbom.cdx.json @@ -180,6 +199,7 @@ cyclonedx-cli validate --input-file armis-cli-linux-amd64.tar.gz.sbom.cdx.json ``` **Learn more:** + - [SLSA Framework](https://slsa.dev/) - [Sigstore Cosign](https://docs.sigstore.dev/cosign/overview/) - [CycloneDX SBOM](https://cyclonedx.org/) @@ -189,16 +209,19 @@ cyclonedx-cli validate --input-file armis-cli-linux-amd64.tar.gz.sbom.cdx.json ## Quick Start ### Set up authentication + ```bash export ARMIS_API_TOKEN="your-api-token-here" ``` ### Scan a repository + ```bash armis-cli scan repo ./my-project ``` ### Scan a container image + ```bash armis-cli scan image nginx:latest ``` @@ -208,7 +231,8 @@ armis-cli scan image nginx:latest ## Usage ### Global Flags -``` + +```text --token string API token for authentication (or use ARMIS_API_TOKEN env var) --api-url string Armis Cloud API base URL (default: https://api.armis.cloud/v1) --format string Output format: human, json, sarif, junit (default: human) @@ -218,24 +242,32 @@ armis-cli scan image nginx:latest ``` ### Scan Repository + Scans a local directory, creates a tarball, and uploads to Armis Cloud for analysis. + ```bash armis-cli scan repo [path] --tenant-id [tenant-id] ``` + **Size Limit**: 2GB **Example**: + ```bash armis-cli scan repo ./my-app --tenant-id my-tenant --format json --fail-on HIGH,CRITICAL ``` ### Scan Container Image + Scans a container image (local or remote) or a tarball. + ```bash armis-cli scan image [image-name] --tenant-id [tenant-id] armis-cli scan image --tarball [path-to-tarball] --tenant-id [tenant-id] ``` + **Size Limit**: 5GB **Examples**: + ```bash # Scan remote image armis-cli scan image nginx:latest --tenant-id my-tenant @@ -250,25 +282,33 @@ armis-cli scan image --tarball ./image.tar --tenant-id my-tenant ## Output Formats ### Human-Readable (Default) + Colorful, formatted output with tables and summaries. + ```bash armis-cli scan repo ./my-app ``` ### JSON + Machine-readable JSON output. + ```bash armis-cli scan repo ./my-app --format json ``` ### SARIF + Static Analysis Results Interchange Format for tool integration. + ```bash armis-cli scan repo ./my-app --format sarif > results.sarif ``` ### JUnit XML + Test report format for CI/CD integration. + ```bash armis-cli scan repo ./my-app --format junit > results.xml ``` @@ -302,6 +342,7 @@ jobs: ``` **Available inputs:** + | Input | Type | Default | Description | |-------|------|---------|-------------| | `scan-type` | string | `repo` | Type of scan: `repo` or `image` | @@ -313,6 +354,7 @@ jobs: | `image-tarball` | string | | Path to image tarball (for image scans) | **Required secrets:** + - `api-token`: Armis API token for authentication - `tenant-id`: Tenant identifier for Armis Cloud @@ -359,6 +401,7 @@ jobs: ``` ### GitLab CI + ```yaml security-scan: stage: test @@ -373,6 +416,7 @@ security-scan: ``` ### Jenkins + ```groovy pipeline { agent any @@ -394,6 +438,7 @@ pipeline { ``` ### Azure DevOps + ```yaml trigger: - main @@ -415,6 +460,7 @@ steps: ``` ### CircleCI + ```yaml version: 2.1 jobs: @@ -439,6 +485,7 @@ workflows: ``` ### BitBucket Pipelines + ```yaml pipelines: default: @@ -515,16 +562,19 @@ Visit the [releases page](https://github.com/ArmisSecurity/armis-cli/releases) t --- ## Building from Source + ```bash git clone https://github.com/ArmisSecurity/armis-cli.git cd armis-cli make build ``` + The binary will be in `bin/armis-cli`. --- ## Development + ```bash # Run tests make test @@ -537,7 +587,9 @@ make release --- ## Contributing + We welcome contributions! Please see: + - [CONTRIBUTING.md](.github/CONTRIBUTING.md) for contribution guidelines - [CODE_OF_CONDUCT.md](.github/CODE_OF_CONDUCT.md) for community standards - [Issue Templates](.github/ISSUE_TEMPLATE/) for reporting bugs or requesting features @@ -545,13 +597,15 @@ We welcome contributions! Please see: --- ## Support + - For issues, open a [GitHub Issue](https://github.com/ArmisSecurity/armis-cli/issues) - For security concerns, see [SECURITY.md](.github/SECURITY.md) -- For questions, contact support@armis.com +- For questions, contact --- ## License + This CLI is open source software licensed under the Apache License 2.0. It is intended to be used as a client for interacting with the Armis cloud platform APIs. The CLI itself does not contain any proprietary detection logic or security analysis engines. Use of the CLI is subject to the terms of service of the corresponding cloud APIs. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f64724e..b132338 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - Initial public release - Repository scanning for security vulnerabilities - Container image scanning @@ -32,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Release History -