Skip to content

Azure Pipelines advanced patterns: API gate, UI publishing, central template#5

Merged
levine-cycode merged 2 commits into
mainfrom
feature/azure-cycode-advanced-patterns
Apr 22, 2026
Merged

Azure Pipelines advanced patterns: API gate, UI publishing, central template#5
levine-cycode merged 2 commits into
mainfrom
feature/azure-cycode-advanced-patterns

Conversation

@appsechq-brian
Copy link
Copy Markdown
Member

Summary

Reference copy of three Azure Pipelines integration patterns that extend the existing CLI gate. Customer-facing doc: se-copilot/artifacts/azure-pipelines-cycode-advanced-patterns.md.

Replaces #4 (that branch inherited unrelated local commits). This one is based cleanly on origin/main — two commits, only the Azure work.

Patterns

  • API gatescripts/cycode-gate.sh queries the Cycode RIG Graph API for Open violations in a named repo and exits non-zero on match. Tunable via SEVERITY_MIN, CATEGORY, RISK_SCORE_MIN. Live-tested against levine-se-playground.
  • Results in Azure UIscripts/cycode-json-to-junit.py + scripts/cycode-summary.py convert cycode -o json scan ... output for PublishTestResults@2 (Tests tab) and ##vso[task.uploadsummary] (custom tab). Raw JSON also published via PublishBuildArtifacts@1.
  • Centralized templatetemplates/cycode-scan.yml owns the scan + publish + gate logic. Consumers extends: it and pass parameters. Cross-repo usage documented in the template header.

Example pipelines

File Purpose
azure-pipelines-api-gate.yml Standalone API gate
azure-pipelines-publish-results.yml All three UI surfaces populated from one scan
azure-pipelines-template-consumer.yml Minimal consumer of templates/cycode-scan.yml

Gotchas captured

  • RIG's detection_details.repository_name stores the bare repo name (vectorvictor), not owner/repo. Verified 2026-04-22.
  • Each .result[] in RIG wraps the detection in a .resource object — jq paths must drill through it.
  • Script flags at least N (page cap hit) when fast_query_has_more=true, so the logged count is truthful when there are more than 200 findings.

Secrets

Azure DevOps pipeline secrets: CYCODE_CLIENT_ID, CYCODE_CLIENT_SECRET (ideally via Variable Group backed by Key Vault).

Test plan

  • scripts/cycode-gate.sh returns non-zero for vectorvictor against levine-se-playground
  • Field resolution in gate output verified against real RIG shape
  • Deploy to customer's test Azure DevOps project with self-hosted agent; run each of the three pipelines and verify Tests tab, custom summary tab, artifact, and gate behavior
  • Refactor template into a separate repo and validate cross-repo resources.repositories + extends pattern

…centralized template

Three new patterns complementing the existing CLI gate in azure-pipelines.yml:

- scripts/cycode-gate.sh — queries the Cycode RIG Graph API for Open
  violations in a named repo; fails the build if any match. Filters by
  severity, category, and risk score via env vars. Emits
  ##vso[task.logissue] for Azure Pipelines.

- scripts/cycode-json-to-junit.py + scripts/cycode-summary.py —
  converters that take `cycode -o json scan ...` output and produce
  JUnit XML (for PublishTestResults@2 → Tests tab) and a Markdown
  report (for ##vso[task.uploadsummary] → custom tab on build summary).

- templates/cycode-scan.yml — centralized template consumed via
  `extends`. App pipelines pass parameters (scanPath, scanTypeFlags,
  severityThreshold, repoName, gateMode) and inherit the scan +
  publish + gate logic. Cross-repo usage documented in the header.

Example pipelines:
- azure-pipelines-api-gate.yml           — API gate standalone
- azure-pipelines-publish-results.yml    — Tests tab + summary + artifact
- azure-pipelines-template-consumer.yml  — minimal consumer of the template
- RIG .result[] items wrap detections in a .resource object; updated the
  jq filter to drill through it so severity/risk_score/policy/file_path
  render correctly instead of all dashes.
- Use bare repo name ("vectorvictor") in defaults and docs — the
  owner/repo form returns 0 results in RIG.
- Check .fast_query_has_more and surface "at least N (page cap hit)"
  when results are paginated, so the gate message is truthful when the
  tenant has more than page_size findings.
Comment thread scripts/cycode-summary.py


def main(src: str) -> int:
with open(src) as f:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycode: SAST violation: 'Unsanitized user input in file path'.

Severity: High

Description

Unsanitized user input in file path resolution can lead to security vulnerabilities. This issue arises when an application directly uses input from the user to determine file paths or names without proper validation or sanitization. Attackers can exploit this to access unauthorized files or directories, leading to data breaches or other security compromises.

Cycode Remediation Guideline

✅ Do


  • Do use a safelist to define accessible paths or directories. Only allow user input to influence file paths within these predefined, safe boundaries.
  • Do sanitize user input used in file path resolution. For example, use absolute paths and check against the expected base directory
      BASE_DIRECTORY = '/path/to/safe/directory'
      my_path = os.path.abspath(os.path.join(BASE_DIRECTORY, user_input))
    
      if my_path.startswith(BASE_DIRECTORY):
        open(my_path)

❌ Don't


  • Do not directly use user input in file paths without sanitization. Failure to sanitize could allow attackers to manipulate file paths and to access or manipulate unauthorized files.

🎥 Learning materials (by Secure Code Warrior)


Tell us how you wish to proceed using one of the following commands:

Tag Short Description
#cycode_sast_ignore_here <reason> Ignore this violation — applies to this violation only
#cycode_ai_remediation Request remediation guidance using Cycode AI
#cycode_sast_false_positive <reason> Mark as false positive — applies to this violation only

⚠️ When commenting on Github, you may need to refresh the page to see the latest updates.


out.append("</testsuite>")

with open(dst, "w") as f:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycode: SAST violation: 'Unsanitized user input in file path'.

Severity: High

Description

Unsanitized user input in file path resolution can lead to security vulnerabilities. This issue arises when an application directly uses input from the user to determine file paths or names without proper validation or sanitization. Attackers can exploit this to access unauthorized files or directories, leading to data breaches or other security compromises.

Cycode Remediation Guideline

✅ Do


  • Do use a safelist to define accessible paths or directories. Only allow user input to influence file paths within these predefined, safe boundaries.
  • Do sanitize user input used in file path resolution. For example, use absolute paths and check against the expected base directory
      BASE_DIRECTORY = '/path/to/safe/directory'
      my_path = os.path.abspath(os.path.join(BASE_DIRECTORY, user_input))
    
      if my_path.startswith(BASE_DIRECTORY):
        open(my_path)

❌ Don't


  • Do not directly use user input in file paths without sanitization. Failure to sanitize could allow attackers to manipulate file paths and to access or manipulate unauthorized files.

🎥 Learning materials (by Secure Code Warrior)


Tell us how you wish to proceed using one of the following commands:

Tag Short Description
#cycode_sast_ignore_here <reason> Ignore this violation — applies to this violation only
#cycode_ai_remediation Request remediation guidance using Cycode AI
#cycode_sast_false_positive <reason> Mark as false positive — applies to this violation only

⚠️ When commenting on Github, you may need to refresh the page to see the latest updates.



def main(src: str, dst: str) -> int:
with open(src) as f:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycode: SAST violation: 'Unsanitized user input in file path'.

Severity: High

Description

Unsanitized user input in file path resolution can lead to security vulnerabilities. This issue arises when an application directly uses input from the user to determine file paths or names without proper validation or sanitization. Attackers can exploit this to access unauthorized files or directories, leading to data breaches or other security compromises.

Cycode Remediation Guideline

✅ Do


  • Do use a safelist to define accessible paths or directories. Only allow user input to influence file paths within these predefined, safe boundaries.
  • Do sanitize user input used in file path resolution. For example, use absolute paths and check against the expected base directory
      BASE_DIRECTORY = '/path/to/safe/directory'
      my_path = os.path.abspath(os.path.join(BASE_DIRECTORY, user_input))
    
      if my_path.startswith(BASE_DIRECTORY):
        open(my_path)

❌ Don't


  • Do not directly use user input in file paths without sanitization. Failure to sanitize could allow attackers to manipulate file paths and to access or manipulate unauthorized files.

🎥 Learning materials (by Secure Code Warrior)


Tell us how you wish to proceed using one of the following commands:

Tag Short Description
#cycode_sast_ignore_here <reason> Ignore this violation — applies to this violation only
#cycode_ai_remediation Request remediation guidance using Cycode AI
#cycode_sast_false_positive <reason> Mark as false positive — applies to this violation only

⚠️ When commenting on Github, you may need to refresh the page to see the latest updates.

@levine-cycode levine-cycode merged commit ebfb9a2 into main Apr 22, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants