Skip to content

Feature/security gate - #28

Merged
JAugusto42 merged 6 commits into
mainfrom
feature/security-gate
Jul 29, 2026
Merged

Feature/security gate#28
JAugusto42 merged 6 commits into
mainfrom
feature/security-gate

Conversation

@JAugusto42

@JAugusto42 JAugusto42 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch adds a new security gate command to the CLI, letting a pipeline check an asset's vulnerabilities against policy thresholds and fail the build if they're exceeded.

  • New command: conviso security-gate, with two ways to run it:
    • Platform mode (default): asks the Conviso Platform for the PASS/FAIL decision (securityGateRun query). The platform applies its own configured rules and returns which vulnerabilities caused the failure.
    • Local rules mode (--rules-file): reads a YAML file with severity thresholds (e.g. "block if more than 0 critical, more than 5 high"), validates it against a JSON Schema, fetches live vulnerability counts (issuesStats), and evaluates the rules locally. Supports an optional grace period per severity (max_days_to_fix) so newly found issues aren't blocked immediately.
  • Branch filtering (--branch / -b): scopes the evaluation to a specific branch, in both modes above.
    • Platform mode resolves the branch name to an ID first (new BranchLookup query), then passes it to the gate query.
    • Local rules mode passes the branch name directly to issuesStats.
    • Requires --company-id. Branch names are matched case-sensitively; an unknown branch fails with a clear error listing the available branches.
    • Legacy vulnerabilities with no branch recorded are excluded from the evaluation when --branch is used — the command warns about this explicitly every time.
  • Output: results are shown in the terminal as Rich tables, and can optionally be written to a JSON file with --output.
  • Error handling: any technical failure (network, timeout, auth, invalid asset/branch) always exits non-zero and is clearly labeled as a technical error — never confused with a "gate passed" result.
  • Supporting changes:
    • Added jsonschema as a dependency (rules file validation).
    • client_graphql.py now supports a CONVISO_API_URL override (used to test against staging); production remains the default when unset.
    • Registered security-gate as a direct top-level command (not a subcommand group) and added it to the list of commands requiring authentication.
  • Includes one unrelated, isolated one-line fix (separate commit f17a07b): corrected a pre-existing broken import in tests/test_batch_findings.py (from src.conviso...from conviso...).

Usage

# Platform mode
conviso security-gate --asset-id 31894

# Local rules mode
conviso security-gate --asset-id 31894 --company-id 11 --rules-file rules.yaml

# Scoped to a branch
conviso security-gate --asset-id 31894 --company-id 11 --branch feature/my-feature

# Export full result as JSON
conviso security-gate --asset-id 31894 --output gate-result.json

Testing

  • Automated Tests
    • Full suite: python -m pytest -v78/78 passing
    • Covers: YAML parsing and schema validation, rule evaluation (pass/fail/edge cases), SLA/timezone handling, both execution flows (mocked API), branch resolution (found/not found/case-sensitivity/network errors), CLI parameter validation, and formatter output.
  • Manual Checks
    • Verified against staging (CONVISO_API_URL override):
      • Platform flow: PASS and FAIL scenarios, with and without --branch.
      • Local rules flow: PASS and FAIL scenarios, with and without --branch, including max_days_to_fix.
      • --branch without --company-id → exit 1, clear error.
      • Unknown branch → exit 1, lists available branches for the asset.
      • --output JSON export produces a complete result file.
      • Confirmed default (unset CONVISO_API_URL) still points to production.
      • Confirmed conviso security-gate --help shows options directly, with no subcommand required.

Notes

  • Diagnostic script tools/check_security_gate_field.py was used during discovery to confirm securityGateRun and branch-related fields exist on the staging GraphQL schema before implementation started.
  • Follow-up (out of scope for this PR): auto-detect the branch from common CI environment variables (GITHUB_REF_NAME, CI_COMMIT_REF_NAME) when --branch/CONVISO_BRANCH aren't set.
  • Every execution with --branch makes one extra GraphQL call (BranchLookup) before the main gate query — accepted trade-off, not optimized in this PR.
  • Full test plan, including rationale and edge cases, is checked in at docs/security_gate_test_plan.md.

Checklist

  • Updated README/docs if user-facing changes (test plan document provided; README update tracked separately)
  • Error handling returns non-zero exit on failures
    • Gate FAIL, branch not found, BranchLookup network/API errors, and missing --company-id all exit 1, with messages that distinguish technical errors from policy failures.

Port the security gate feature from convisocli to conviso-cli, supporting
two evaluation flows:

- Platform flow: delegates to the Conviso Platform via the securityGateRun
  GraphQL query, with full pagination over failingVulnerabilities.
- Local YAML flow: validates a user-provided rules file against a JSON
  Schema and evaluates severity thresholds locally using issuesStats,
  including max_days_to_fix SLA support with UTC-aware datetime handling.

Adds a Rich-based formatter for terminal output, JSON export via --output,
and a diagnostic script (tools/check_security_gate_field.py) used to
confirm securityGateRun availability on the staging GraphQL schema.

- Add jsonschema>=4.0 dependency for rules file validation
- Add CONVISO_API_URL env var support to client_graphql.py (defaults to
  production, allows pointing to staging for manual verification)
- Register security-gate command and add it to commands_requiring_auth
- Add 46 tests covering YAML parsing, schema validation, rule evaluation,
  timezone edge cases, formatter output, and both flows via mocked
  GraphQL calls

All 46 tests passing.
The import used 'from src.conviso...' which breaks when the package is
installed in editable mode (pip install -e .). The 'src' layout prefix is
resolved by setuptools and is not exposed as a Python module name.

This was a pre-existing issue on main unrelated to the security-gate feature.
Allows scoping the security gate evaluation to a specific branch.
Vulnerabilities without branch association (legacy/NULL-branch) are
excluded when --branch is used; a warning is printed to inform the user.

Changes:
- New --branch / -b option (envvar: CONVISO_BRANCH)
  - Requires --company-id (validated manually, same pattern as --rules-file)
  - Case-sensitive match (per API contract)
  - Warning emitted before gate result about legacy vuln exclusion
- New BranchLookup GraphQL query (branches(companyId, assetId))
- New _resolve_branch_id() helper
  - Distinct exit messages: 'technical error' (network/500) vs
    'branch not found' (lists available branches)
  - Never silently passes the gate on failure
- Platform flow: passes branchId (ID) resolved via BranchLookup
  - Pagination (_fetch_all_failing_pages) propagates branchId
  - Restored log_request=True, verbose_only=True on pagination call
    (accidentally dropped in prior edit, now restored)
- YAML/local flow: passes branchNames: [branch] directly to issuesStats
  (no ID lookup needed — API accepts name directly)
- Output JSON includes 'branch' field in local-rules mode
- 14 new tests covering BRANCH-01 through BRANCH-08
- docs/security_gate_test_plan.md: full test plan with branch cases,
  exit criteria, no-credentials policy, and follow-up items

Note: every --branch execution adds one extra GraphQL call for the
branch lookup. Auto-detection from CI env vars is a planned follow-up.
@JAugusto42 JAugusto42 self-assigned this Jul 29, 2026
@JAugusto42
JAugusto42 merged commit ad89298 into main Jul 29, 2026
2 checks passed
@JAugusto42
JAugusto42 deleted the feature/security-gate branch July 29, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants