# pylynk

pylynk is the official command-line interface for the Interlynk platform. It provides programmatic access to SBOM upload, download, product management, vulnerability queries, and processing status checks — designed for both interactive use and CI/CD automation.

**Repository:** [github.com/interlynk-io/pylynk](https://github.com/interlynk-io/pylynk)

***

## When to Use pylynk

| Use Case                      | pylynk      | API (curl)  | UI             |
| ----------------------------- | ----------- | ----------- | -------------- |
| CI/CD SBOM upload             | Recommended | Possible    | Not practical  |
| Bulk vulnerability export     | Recommended | Possible    | Manual         |
| Interactive product browsing  | Good        | Verbose     | Best           |
| SBOM download with enrichment | Recommended | Complex     | Manual         |
| One-off queries               | Good        | Good        | Good           |
| Scripted automation           | Recommended | Recommended | Not applicable |

Use pylynk when you need repeatable, scriptable access to the platform. Use the API directly when you need fine-grained control over GraphQL queries. Use the UI for visual exploration and ad hoc operations.

***

## Installation

### pip (from source)

```bash
git clone https://github.com/interlynk-io/pylynk.git
cd pylynk
pip3 install -r requirements.txt
python3 pylynk.py --help
```

### Docker

```bash
# Pull the latest image
docker pull ghcr.io/interlynk-io/pylynk:latest

# Run a command
docker run -e INTERLYNK_SECURITY_TOKEN=$INTERLYNK_SECURITY_TOKEN \
  -v $(pwd):/app/data \
  ghcr.io/interlynk-io/pylynk:latest upload --prod 'my-app' --sbom /app/data/sbom.json
```

### Verify Installation

```bash
python3 pylynk.py version
```

Expected output:

```
pylynk version: v0.x.x
```

***

## Authentication

### Environment Variable (Recommended)

```bash
export INTERLYNK_SECURITY_TOKEN="lynk_service_your_token_here"
```

This is the recommended method for both local use and CI/CD. The token is read automatically by all commands.

### Command-Line Flag

```bash
python3 pylynk.py prods --token "lynk_service_your_token_here"
```

{% hint style="warning" %}
Avoid `--token` in CI/CD — the value may appear in build logs. Always use the environment variable.
{% endhint %}

### API Endpoint Override

The default API endpoint is `https://api.interlynk.io/lynkapi`. Override it with:

```bash
export INTERLYNK_API_URL="https://custom-api.example.com/lynkapi"
```

### Token Security Best Practices

* Store tokens in a secrets manager (Vault, AWS Secrets Manager, GitHub Secrets).
* Never commit tokens to source control.
* Use service tokens for automation; user tokens for interactive sessions.
* Set expiration dates — 90 days for CI/CD, 30 days for development.
* Rotate tokens proactively. See [Rotation Strategy](/administration/api-key-management.md#rotation-strategy).

***

## Core Commands

### prods — List Products

Lists all products in the organization.

```bash
python3 pylynk.py prods
python3 pylynk.py prods --output json
python3 pylynk.py prods --output csv
python3 pylynk.py prods --human-time
```

| Parameter       | Required | Default | Description                                   |
| --------------- | -------- | ------- | --------------------------------------------- |
| `--output`      | No       | `table` | Output format: `table`, `json`, `csv`         |
| `--human-time`  | No       | Off     | Show relative timestamps (e.g., "2 days ago") |
| `--token`       | No       | Env var | Override authentication token                 |
| `-v, --verbose` | No       | Off     | Enable debug output                           |

**Output columns:** NAME, ID, VERSIONS, UPDATED AT

***

### vers — List Versions

Lists all versions (SBOMs) for a product.

```bash
python3 pylynk.py vers --prod 'my-app'
python3 pylynk.py vers --prod 'my-app' --env 'production' --output json
```

| Parameter       | Required | Default   | Description                           |
| --------------- | -------- | --------- | ------------------------------------- |
| `--prod`        | Yes      | —         | Product name                          |
| `--env`         | No       | `default` | Environment name                      |
| `--output`      | No       | `table`   | Output format: `table`, `json`, `csv` |
| `--human-time`  | No       | Off       | Relative timestamps                   |
| `-v, --verbose` | No       | Off       | Debug output                          |

**Output columns:** ID, VERSION, PRIMARY COMPONENT, UPDATED AT

Use the `ID` value from this output as `--verId` in other commands.

***

### upload — Upload SBOM

Uploads an SBOM file to the platform.

```bash
# Upload to default environment
python3 pylynk.py upload --prod 'my-app' --sbom sbom.json

# Upload to a specific environment
python3 pylynk.py upload --prod 'my-app' --env 'production' --sbom sbom.json

# Upload with custom retry count
python3 pylynk.py upload --prod 'my-app' --sbom sbom.json --retries 5
```

| Parameter       | Required | Default   | Description                       |
| --------------- | -------- | --------- | --------------------------------- |
| `--prod`        | Yes      | —         | Product name                      |
| `--sbom`        | Yes      | —         | Path to SBOM file                 |
| `--env`         | No       | `default` | Target environment                |
| `--retries`     | No       | `3`       | Retry count on transient failures |
| `-v, --verbose` | No       | Off       | Debug output                      |

**Supported formats:** CycloneDX (JSON, XML), SPDX (JSON, tag-value)

**Retry behavior:**

| Condition        | Behavior                                      |
| ---------------- | --------------------------------------------- |
| 5xx server error | Retries with exponential backoff (1s, 2s, 4s) |
| 429 rate limit   | Retries with exponential backoff              |
| 401 unauthorized | Fails immediately — no retry                  |
| Other 4xx        | Fails immediately — no retry                  |
| Network error    | Retries with exponential backoff              |

**CI metadata:** When running in a CI environment (`CI=true`), pylynk automatically captures build metadata (PR number, commit SHA, branch name, build URL) and sends it as HTTP headers with the upload.

***

### download — Download SBOM

Downloads an SBOM from the platform, optionally enriched with vulnerabilities, support status, or converted to a different format.

```bash
# Download by version ID
python3 pylynk.py download --verId 'abc-123' --out-file sbom.json

# Download by product/environment/version
python3 pylynk.py download --prod 'my-app' --env 'default' --ver 'v1.0.0' --out-file sbom.json

# Download with vulnerabilities included
python3 pylynk.py download --verId 'abc-123' --vuln true --out-file enriched.json

# Download in a specific format
python3 pylynk.py download --verId 'abc-123' --spec CycloneDX --spec-version 1.5

# Download the original uploaded SBOM (unmodified)
python3 pylynk.py download --verId 'abc-123' --original --out-file original.json

# Download a lite version
python3 pylynk.py download --verId 'abc-123' --lite --out-file lite.json

# Include support status metadata
python3 pylynk.py download --verId 'abc-123' --include-support-status --out-file sbom.json

# Export support levels only (CSV)
python3 pylynk.py download --verId 'abc-123' --support-level-only --out-file support.csv
```

**Identification — provide one of:**

| Method        | Parameters Required          |
| ------------- | ---------------------------- |
| By version ID | `--verId`                    |
| By name       | `--prod` + `--env` + `--ver` |

| Parameter                  | Required    | Default  | Description                              |
| -------------------------- | ----------- | -------- | ---------------------------------------- |
| `--verId`                  | Conditional | —        | Version ID (from `vers` command output)  |
| `--prod`                   | Conditional | —        | Product name                             |
| `--env`                    | Conditional | —        | Environment name                         |
| `--ver`                    | Conditional | —        | Version name                             |
| `--out-file`               | No          | stdout   | Output file path                         |
| `--vuln`                   | No          | `false`  | Include vulnerabilities (`true`/`false`) |
| `--spec`                   | No          | Original | Output spec: `SPDX` or `CycloneDX`       |
| `--spec-version`           | No          | Original | Spec version (e.g., `2.3`, `1.5`)        |
| `--lite`                   | No          | Off      | Download lightweight version             |
| `--original`               | No          | Off      | Download exact uploaded SBOM             |
| `--dont-package-sbom`      | No          | Off      | Keep multi-SBOM files separate           |
| `--exclude-parts`          | No          | Off      | Exclude linked parts                     |
| `--include-support-status` | No          | Off      | Add support status metadata              |
| `--support-level-only`     | No          | Off      | CSV output with support levels only      |

***

### vulns — List Vulnerabilities

Queries vulnerabilities across products.

```bash
# All vulnerabilities for a product
python3 pylynk.py vulns --prod 'my-app'

# With vulnerability and VEX details
python3 pylynk.py vulns --prod 'my-app' --vuln-details --vex-details

# Specific version
python3 pylynk.py vulns --prod 'my-app' --verId 'abc-123'

# JSON export
python3 pylynk.py vulns --prod 'my-app' --output json > vulns.json

# CSV export for spreadsheet analysis
python3 pylynk.py vulns --prod 'my-app' --output csv > vulns.csv

# Custom column selection
python3 pylynk.py vulns --prod 'my-app' --columns 'id,component_name,severity,cvss,status'

# List all available columns
python3 pylynk.py vulns --list-columns
```

| Parameter             | Required | Default     | Description                                                |
| --------------------- | -------- | ----------- | ---------------------------------------------------------- |
| `--prod`              | No       | —           | Product name (uses latest version if no version specified) |
| `--env`               | No       | `default`   | Environment name                                           |
| `--verId`             | No       | —           | Specific version ID                                        |
| `--ver`               | No       | —           | Version name                                               |
| `--output`            | No       | `table`     | Output format: `table`, `json`, `csv`                      |
| `--columns`           | No       | Default set | Comma-separated column names                               |
| `--vuln-details`      | No       | Off         | Include severity, CVSS, EPSS, KEV, CWE                     |
| `--vex-details`       | No       | Off         | Include VEX status, justification, actions                 |
| `--timestamp-details` | No       | Off         | Include all timestamp columns                              |
| `--human-time`        | No       | Off         | Relative timestamps                                        |
| `--list-columns`      | No       | —           | Display available column names and exit                    |

**Default columns:** id, part\_name, part\_version, component\_name, component\_version, severity, source, status, assigned

**Vulnerability detail columns (`--vuln-details`):** severity, kev, cvss, cvss\_vector, epss, cwe

**VEX detail columns (`--vex-details`):** status, details, justification, action\_statement, impact\_statement, response

***

### status — Check Processing Status

Checks the processing status of an uploaded SBOM.

```bash
python3 pylynk.py status --prod 'my-app' --verId 'abc-123'
python3 pylynk.py status --prod 'my-app' --env 'production' --ver 'v1.0.0'
```

| Parameter  | Required    | Default   | Description                     |
| ---------- | ----------- | --------- | ------------------------------- |
| `--prod`   | Yes         | —         | Product name                    |
| `--verId`  | Conditional | —         | Version ID                      |
| `--ver`    | Conditional | —         | Version name (requires `--env`) |
| `--env`    | No          | `default` | Environment name                |
| `--output` | No          | `table`   | Output format: `table`, `json`  |

**Status types tracked:**

| Status           | Description                    |
| ---------------- | ------------------------------ |
| checksStatus     | SBOM quality and format checks |
| policyStatus     | Policy evaluation              |
| labelingStatus   | Internal labeling              |
| automationStatus | Automation rule execution      |
| vulnScanStatus   | Vulnerability scanning         |

**Status values:** `UNKNOWN`, `NOT_STARTED`, `IN_PROGRESS`, `COMPLETED`

***

### version — Show CLI Version

```bash
python3 pylynk.py version
```

***

## CI/CD Integration

### GitHub Actions

```yaml
name: Upload SBOM
on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  upload-sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Generate SBOM
        run: |
          # Use your preferred SBOM generator
          syft . -o cyclonedx-json > sbom.cdx.json

      - name: Upload SBOM to Interlynk
        env:
          INTERLYNK_SECURITY_TOKEN: ${{ secrets.INTERLYNK_SERVICE_TOKEN }}
        run: |
          pip3 install -r requirements.txt
          python3 pylynk.py upload --prod '${{ github.event.repository.name }}' --sbom sbom.cdx.json
```

### GitLab CI

```yaml
upload-sbom:
  stage: deploy
  image: python:3.11
  variables:
    INTERLYNK_SECURITY_TOKEN: $INTERLYNK_SERVICE_TOKEN
  script:
    - pip3 install -r requirements.txt
    - python3 pylynk.py upload --prod 'my-app' --sbom sbom.cdx.json
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_TAG'
```

### Bitbucket Pipelines

```yaml
pipelines:
  branches:
    main:
      - step:
          name: Upload SBOM
          image: python:3.11
          script:
            - pip3 install -r requirements.txt
            - python3 pylynk.py upload --prod 'my-app' --sbom sbom.cdx.json
  tags:
    'v*':
      - step:
          name: Upload Release SBOM
          image: python:3.11
          script:
            - pip3 install -r requirements.txt
            - python3 pylynk.py upload --prod 'my-app' --sbom sbom.cdx.json
```

### Azure DevOps

```yaml
trigger:
  branches:
    include: [main]
  tags:
    include: ['v*']

steps:
  - script: pip3 install -r requirements.txt
    displayName: 'Install pylynk'
  - script: python3 pylynk.py upload --prod 'my-app' --sbom sbom.cdx.json
    displayName: 'Upload SBOM'
    env:
      INTERLYNK_SECURITY_TOKEN: $(INTERLYNK_SERVICE_TOKEN)
```

### Docker-Based CI

For environments where Python installation is not practical:

```yaml
# GitHub Actions with Docker
- name: Upload SBOM
  run: |
    docker run --rm \
      -e INTERLYNK_SECURITY_TOKEN=${{ secrets.INTERLYNK_SERVICE_TOKEN }} \
      -v $(pwd):/app/data \
      ghcr.io/interlynk-io/pylynk:latest \
      upload --prod 'my-app' --sbom /app/data/sbom.cdx.json
```

### Handling Secrets Securely

| CI Platform    | Secret Storage                 | Reference Syntax                         |
| -------------- | ------------------------------ | ---------------------------------------- |
| GitHub Actions | Repository Secrets             | `${{ secrets.INTERLYNK_SERVICE_TOKEN }}` |
| GitLab CI      | CI/CD Variables (masked)       | `$INTERLYNK_SERVICE_TOKEN`               |
| Bitbucket      | Repository Variables (secured) | `$INTERLYNK_SERVICE_TOKEN`               |
| Azure DevOps   | Pipeline Variables (secret)    | `$(INTERLYNK_SERVICE_TOKEN)`             |

{% hint style="warning" %}
Always mark the variable as **secret/masked** in your CI platform to prevent it from appearing in build logs.
{% endhint %}

### Fail-the-Build Patterns

Use exit codes to gate builds on SBOM upload success:

```bash
# Fail if upload fails
python3 pylynk.py upload --prod 'my-app' --sbom sbom.json || exit 1

# Upload and verify processing completed
python3 pylynk.py upload --prod 'my-app' --sbom sbom.json
sleep 10
python3 pylynk.py status --prod 'my-app' --verId "$VERSION_ID" --output json | \
  python3 -c "import sys, json; d=json.load(sys.stdin); sys.exit(0 if all(s=='COMPLETED' for s in d.values()) else 1)"
```

### CI Metadata

When `CI=true` is set (automatically by most CI platforms), pylynk captures build metadata and sends it with uploads:

| Header               | Description                                 |
| -------------------- | ------------------------------------------- |
| `X-CI-Provider`      | CI platform name                            |
| `X-Event-Type`       | Trigger type (push, pull\_request, release) |
| `X-PR-Number`        | Pull request number                         |
| `X-Commit-SHA`       | Git commit hash                             |
| `X-Repository-URL`   | Repository URL                              |
| `X-Build-URL`        | Build/job URL                               |
| `X-PR-Source-Branch` | Source branch name                          |
| `X-PR-Target-Branch` | Target branch name                          |

Control metadata collection:

```bash
export PYLYNK_INCLUDE_CI_METADATA=auto   # Default — enabled only in CI
export PYLYNK_INCLUDE_CI_METADATA=true   # Force enable
export PYLYNK_INCLUDE_CI_METADATA=false  # Disable
```

***

## Troubleshooting

### Debug Mode

Enable verbose logging with `-v` or `--verbose`:

```bash
python3 pylynk.py upload --prod 'my-app' --sbom sbom.json -v
python3 pylynk.py prods -vv  # More detailed output
```

Debug output includes: API request/response details, token validation (masked), CI metadata detection, upload speed metrics, and timing information.

### Common Errors

| Error                                  | Cause                              | Resolution                                                   |
| -------------------------------------- | ---------------------------------- | ------------------------------------------------------------ |
| `Security token not found`             | `INTERLYNK_SECURITY_TOKEN` not set | Export the environment variable or use `--token`             |
| `Authentication failed`                | Invalid or expired token           | Verify token in UI; create a new one if expired              |
| `Product not found`                    | Typo in product name or no access  | Run `pylynk prods` to list available products                |
| `Version not found`                    | Invalid version ID or name         | Run `pylynk vers --prod 'name'` to list versions             |
| `File not found`                       | Bad SBOM file path                 | Verify path; use absolute paths in Docker                    |
| `Request failed with status code: 429` | Rate limited                       | Automatic retry handles this; increase `--retries` if needed |
| `RequestException`                     | Network or connectivity issue      | Check firewall, proxy, and `INTERLYNK_API_URL`               |
| `Error uploading sbom`                 | Invalid SBOM format                | Verify SBOM is valid CycloneDX or SPDX                       |

### Exit Codes

| Code | Meaning                |
| ---- | ---------------------- |
| `0`  | Success                |
| `1`  | General error          |
| `2`  | Argument parsing error |

***

## Best Practices

### Least Privilege Token Usage

Create service tokens with the minimum role required:

| Workflow                      | Recommended Role                   |
| ----------------------------- | ---------------------------------- |
| SBOM upload only              | Custom role with upload permission |
| Upload + vulnerability review | Operator                           |
| Full automation               | Admin (use sparingly)              |
| Read-only reporting           | Viewer                             |

### Automation Design Patterns

* **Idempotent uploads:** Uploading the same SBOM twice to the same product/environment creates a new version. Design pipelines to upload only on meaningful changes.
* **Environment separation:** Use `--env` to separate staging, production, and development SBOMs.
* **Version tracking:** Capture the version ID from `vers` output after upload for downstream status checks.
* **Error handling:** Always check exit codes. Use `--retries 0` to disable retries when you need fast failure.

### Parallel vs Serial Execution

* **Serial:** Upload SBOMs for the same product sequentially to avoid race conditions on version ordering.
* **Parallel:** Upload SBOMs for different products concurrently. Each product is independent.
* **Status polling:** Wait for `COMPLETED` status before downloading enriched SBOMs. Processing is asynchronous.

***

## Common Misconfigurations

| Issue                         | Symptom                         | Fix                                                  |
| ----------------------------- | ------------------------------- | ---------------------------------------------------- |
| Token in `--token` flag in CI | Token visible in build logs     | Use `INTERLYNK_SECURITY_TOKEN` env var               |
| Wrong `INTERLYNK_API_URL`     | Connection errors or 401        | Verify URL or remove the override to use default     |
| Missing `--prod` on upload    | Argument parsing error          | Always specify `--prod` with upload                  |
| Docker volume not mounted     | File not found inside container | Add `-v $(pwd):/app/data` and use `/app/data/` paths |
| Using `--ver` without `--env` | Version not found               | Provide both `--env` and `--ver` together            |
| Old pylynk version            | Unexpected API errors           | Pull latest from repository or Docker image          |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.interlynk.io/productivity-tools/pylynk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
