Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0a4c589
style: gofmt and goimports fixes for lint
Delqhi Jun 14, 2026
5ac0bd9
test(coverage): remaining test hooks for superpowers, vane, tui/chat …
Delqhi Jun 14, 2026
b989b00
test(coverage): add missing test hooks and tests for tui/chat, superp…
Delqhi Jun 14, 2026
aaeccdc
test(coverage): 100% statement coverage for todo package
Delqhi Jun 15, 2026
0754a8e
test(coverage): 100% statement coverage for superpowers, internal/tui…
Delqhi Jun 15, 2026
cfef82f
feat(skills): bundle 23 project-local skills into sin-code binary
Delqhi Jun 15, 2026
7880df5
chore(deps): add github.com/Songmu/skillsmith for bundled skills
Delqhi Jun 15, 2026
d150dff
style: fix ruff import blank line in validate_skill.py
Delqhi Jun 15, 2026
6dead01
style: fix ruff lint errors across Python codebase
Delqhi Jun 15, 2026
3be5cd1
style: fix pycodestyle E127/E128/E302/E306 in sin_delegate
Delqhi Jun 15, 2026
3c10b55
style: sort imports in test_intelligence_multirepo.py
Delqhi Jun 15, 2026
e486f8d
style: fix ruff/pycodestyle/pyflakes lint errors and go vet sync.Once…
Delqhi Jun 15, 2026
c7cd762
style: fix ruff/pycodestyle/pyflakes across entire repo and go vet sy…
Delqhi Jun 15, 2026
6b091cd
ci: configure git identity and mcp for delegate tests; goimports fixes
Jun 15, 2026
e7417d0
security: fix gosec alerts in todo/audit, todo/id, webui/server (sha1…
Jun 15, 2026
4181bc2
fix: gosec G115/G204 and flaky ledger benchmark threshold
Jun 15, 2026
8970090
feat(skills): add shop-skills category with cj-dropshipping, stripe, …
Jun 15, 2026
ce45db8
chore(skills): add MIT LICENSE files to shop-skills
Jun 15, 2026
293feaa
chore(skills): add context/frameworks/tasks/templates content to shop…
Jun 15, 2026
5499973
feat(skills): add infrastructure-skills category with supabase, cloud…
Jun 15, 2026
cd6fd69
feat(skills): reorganize all bundled skills into category directories…
Jun 15, 2026
03faf1f
style(skills): gofmt flatfs.go
Jun 15, 2026
dc884d8
feat(skills): rename all bundled skills to skill-<category>-<name> an…
Jun 15, 2026
9901bff
test(bench): relax flaky ledger append threshold from 7s to 15s
Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ jobs:
run: go build ./cmd/sin-code
- name: Vet
run: go vet ./cmd/sin-code/... ./cmd/sin-code/internal/...
- name: Setup Python for skill validation
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Validate bundled skills
run: |
pip install pyyaml
python3 scripts/validate_skill.py --all-bundled --strict
- name: Test
run: go test ./cmd/sin-code/ ./cmd/sin-code/internal/ -count=1 -v 2>&1 | tail -50
- name: Test LSP live (build tag, opt-in)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-ci.yml.doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Go CI for the `sin-code` binary.

## What this workflow does

- **go test**: Checks out the repo, sets up Go 1.25.11, installs `gopls`, builds `cmd/sin-code`, runs `go vet`, and runs the Go test suite. It also runs an opt-in LSP live test.
- **go test**: Checks out the repo, sets up Go 1.25.11, installs `gopls`, builds `cmd/sin-code`, runs `go vet`, validates bundled skills, and runs the Go test suite. It also runs an opt-in LSP live test.
- **benchmark**: Runs only benchmarks (`-run='^$'`) in `cmd/sin-code/internal/`, captures the output, and checks that the indexed search is at least 3x faster than the full-scan baseline.

## Related files
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/test-delegate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ jobs:
- name: Install base deps
run: |
python -m pip install --upgrade pip
pip install pytest pytest-asyncio
pip install pytest pytest-asyncio 'mcp>=1.0'
# The package is stdlib-only; expose it on PYTHONPATH
echo "PYTHONPATH=$GITHUB_WORKSPACE/src" >> $GITHUB_ENV

- name: Configure git identity for tests
run: |
git config --global user.email "ci@opensin-code.local"
git config --global user.name "SIN CI"

- name: Run delegate tests
run: |
python -m pytest \
Expand Down
46 changes: 34 additions & 12 deletions SIN-Code-SBOM-Generator/src/sbom_generator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@

import click
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.text import Text
from rich.table import Table

from .generator import SBOMGenerator
from .models import SBOM, SBOMPackage, SBOMMetadata


console = Console()

Expand All @@ -26,16 +23,27 @@
@click.version_option(version="1.0.0", prog_name="sin-sbom")
@click.pass_context
def cli(ctx):
"""SIN-Code SBOM Generator — Generate SPDX and CycloneDX SBOMs.
"""
"""SIN-Code SBOM Generator — Generate SPDX and CycloneDX SBOMs."""
ctx.ensure_object(dict)
ctx.obj["generator"] = SBOMGenerator()


@cli.command()
@click.argument("input_path", type=click.Path(exists=True, dir_okay=False, path_type=Path))
@click.option("--format", "fmt", type=click.Choice(["spdx", "cyclonedx", "both"]), default="both", show_default=True, help="SBOM output format")
@click.option("--output", "-o", type=click.Path(path_type=Path), help="Output directory (default: current directory)")
@click.option(
"--format",
"fmt",
type=click.Choice(["spdx", "cyclonedx", "both"]),
default="both",
show_default=True,
help="SBOM output format",
)
@click.option(
"--output",
"-o",
type=click.Path(path_type=Path),
help="Output directory (default: current directory)",
)
@click.option("--name", default="sbom", show_default=True, help="SBOM document name")
@click.option("--summary", is_flag=True, help="Print human-readable summary")
@click.pass_context
Expand Down Expand Up @@ -68,7 +76,9 @@ def generate(ctx, input_path: Path, fmt: str, output: Optional[Path], name: str,
console.print(f"[green]✅ CycloneDX SBOM written to {cdx_path}[/green]")

if summary:
console.print(Panel(generator.export_summary(sbom), title="SBOM Summary", border_style="blue"))
console.print(
Panel(generator.export_summary(sbom), title="SBOM Summary", border_style="blue")
)

# Print stats table
table = Table(title="SBOM Statistics", show_header=True, header_style="bold magenta")
Expand All @@ -83,9 +93,21 @@ def generate(ctx, input_path: Path, fmt: str, output: Optional[Path], name: str,

@cli.command()
@click.argument("name", default="sbom")
@click.option("--format", "fmt", type=click.Choice(["spdx", "cyclonedx", "both"]), default="both", show_default=True)
@click.option("--output", "-o", type=click.Path(path_type=Path), default=Path("."), help="Output directory")
@click.option("--packages", type=click.STRING, help='JSON array of packages, e.g., \'[{"name":"lodash","version":"4.17.21"}]\'')
@click.option(
"--format",
"fmt",
type=click.Choice(["spdx", "cyclonedx", "both"]),
default="both",
show_default=True,
)
@click.option(
"--output", "-o", type=click.Path(path_type=Path), default=Path("."), help="Output directory"
)
@click.option(
"--packages",
type=click.STRING,
help='JSON array of packages, e.g., \'[{"name":"lodash","version":"4.17.21"}]\'',
)
@click.pass_context
def from_deps(ctx, name: str, fmt: str, output: Path, packages: str):
"""Generate SBOM from a raw list of dependencies (JSON string)."""
Expand Down
106 changes: 68 additions & 38 deletions SIN-Code-SBOM-Generator/src/sbom_generator/cyclonedx_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
Docs: cyclonedx_generator.doc.md
"""

import hashlib
import json
import uuid
import hashlib
from datetime import datetime, timezone
from typing import Dict, List, Any, Optional
from .models import SBOM, SBOMPackage
from typing import Any, Dict

from .models import SBOM, SBOMPackage

CYCLONEDX_SPEC_VERSION = "1.5"
CYCLONEDX_SCHEMA = "http://cyclonedx.org/schema/bom-1.5.schema.json"
Expand All @@ -28,11 +27,13 @@ def generate_cyclonedx(sbom: SBOM) -> Dict[str, Any]:
"version": 1,
"metadata": {
"timestamp": sbom.metadata.timestamp,
"tools": [{
"vendor": "OpenSIN-Code",
"name": sbom.metadata.tool_name,
"version": sbom.metadata.tool_version,
}],
"tools": [
{
"vendor": "OpenSIN-Code",
"name": sbom.metadata.tool_name,
"version": sbom.metadata.tool_version,
}
],
"authors": [{"name": a} for a in sbom.metadata.authors],
},
"components": [],
Expand Down Expand Up @@ -77,47 +78,62 @@ def _package_to_cyclonedx(pkg: SBOMPackage) -> Dict[str, Any]:
component["description"] = pkg.description

if pkg.homepage:
component["externalReferences"] = [{
"type": "website",
"url": pkg.homepage,
}]
component["externalReferences"] = [
{
"type": "website",
"url": pkg.homepage,
}
]

if pkg.checksums:
component["hashes"] = [
{"alg": _map_hash_algo(algo), "content": val}
for algo, val in pkg.checksums.items()
{"alg": _map_hash_algo(algo), "content": val} for algo, val in pkg.checksums.items()
]

# License info
if pkg.license_concluded or pkg.license_declared:
component["licenses"] = []
if pkg.license_concluded:
component["licenses"].append({
"license": {"id": pkg.license_concluded} if _is_spdx_license(pkg.license_concluded) else {"name": pkg.license_concluded}
})
component["licenses"].append(
{
"license": {"id": pkg.license_concluded}
if _is_spdx_license(pkg.license_concluded)
else {"name": pkg.license_concluded}
}
)
if pkg.license_declared and pkg.license_declared != pkg.license_concluded:
component["licenses"].append({
"license": {"id": pkg.license_declared} if _is_spdx_license(pkg.license_declared) else {"name": pkg.license_declared}
})
component["licenses"].append(
{
"license": {"id": pkg.license_declared}
if _is_spdx_license(pkg.license_declared)
else {"name": pkg.license_declared}
}
)

# Vulnerability info (if present)
if pkg.has_vulnerabilities:
if "properties" not in component:
component["properties"] = []
component["properties"].append({
"name": "sin:security:vulnerability_count",
"value": str(pkg.vulnerability_count),
})
component["properties"].append(
{
"name": "sin:security:vulnerability_count",
"value": str(pkg.vulnerability_count),
}
)
if pkg.critical_vulns > 0:
component["properties"].append({
"name": "sin:security:critical_vulns",
"value": str(pkg.critical_vulns),
})
component["properties"].append(
{
"name": "sin:security:critical_vulns",
"value": str(pkg.critical_vulns),
}
)
if pkg.high_vulns > 0:
component["properties"].append({
"name": "sin:security:high_vulns",
"value": str(pkg.high_vulns),
})
component["properties"].append(
{
"name": "sin:security:high_vulns",
"value": str(pkg.high_vulns),
}
)

return component

Expand Down Expand Up @@ -156,17 +172,31 @@ def _is_spdx_license(license_id: str) -> bool:
"""Check if a license identifier is a known SPDX license ID."""
# Simplified check: contains common SPDX licenses or no spaces
known_spdx = {
"MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "GPL-2.0-only",
"GPL-2.0-or-later", "GPL-3.0-only", "GPL-3.0-or-later", "LGPL-2.1-only",
"LGPL-2.1-or-later", "LGPL-3.0-only", "LGPL-3.0-or-later", "MPL-2.0",
"ISC", "Unlicense", "CC0-1.0", "EPL-2.0", "EPL-1.0", "BSL-1.0",
"MIT",
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-2.0-or-later",
"GPL-3.0-only",
"GPL-3.0-or-later",
"LGPL-2.1-only",
"LGPL-2.1-or-later",
"LGPL-3.0-only",
"LGPL-3.0-or-later",
"MPL-2.0",
"ISC",
"Unlicense",
"CC0-1.0",
"EPL-2.0",
"EPL-1.0",
"BSL-1.0",
}
return license_id in known_spdx


def uuid_from_namespace(namespace: str) -> str:
"""Generate a deterministic UUID from a namespace string."""
import hashlib
return str(uuid.UUID(hashlib.md5(namespace.encode()).hexdigest()[:32]))


Expand Down
30 changes: 21 additions & 9 deletions SIN-Code-SBOM-Generator/src/sbom_generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
Docs: generator.doc.md
"""

import json
from typing import List, Dict, Any, Optional
from pathlib import Path
from .models import SBOM, SBOMPackage, SBOMMetadata, ScanResult
from .spdx_generator import spdx_to_json
from typing import Any, Dict, List, Optional

from .cyclonedx_generator import cyclonedx_to_json
from .models import SBOM, SBOMMetadata, SBOMPackage
from .spdx_generator import spdx_to_json


class SBOMGenerator:
Expand All @@ -21,7 +21,9 @@ def __init__(self, tool_name: str = "SIN-Code-SBOM-Generator", tool_version: str
self.tool_name = tool_name
self.tool_version = tool_version

def generate_from_sca_results(self, sca_results: Dict[str, Any], document_name: str = "") -> SBOM:
def generate_from_sca_results(
self, sca_results: Dict[str, Any], document_name: str = ""
) -> SBOM:
"""Generate SBOM from SCA (Software Composition Analysis) scan results.

Args:
Expand Down Expand Up @@ -67,7 +69,9 @@ def generate_from_sca_results(self, sca_results: Dict[str, Any], document_name:
source_files=source_files,
)

def generate_from_raw_dependencies(self, deps: List[Dict[str, Any]], document_name: str = "") -> SBOM:
def generate_from_raw_dependencies(
self, deps: List[Dict[str, Any]], document_name: str = ""
) -> SBOM:
"""Generate SBOM from a raw list of dependencies (e.g., from package.json, requirements.txt).

Args:
Expand Down Expand Up @@ -147,8 +151,14 @@ def export_summary(self, sbom: SBOM) -> str:
"|------|---------|------|---------|-----------------|",
]
for pkg in sbom.packages:
vuln_str = f"{pkg.vulnerability_count} (C:{pkg.critical_vulns} H:{pkg.high_vulns} M:{pkg.medium_vulns})" if pkg.has_vulnerabilities else "0"
lines.append(f"| {pkg.name} | {pkg.version} | {pkg.type} | {pkg.license_concluded or '-'} | {vuln_str} |")
vuln_str = (
f"{pkg.vulnerability_count} (C:{pkg.critical_vulns} H:{pkg.high_vulns} M:{pkg.medium_vulns})"
if pkg.has_vulnerabilities
else "0"
)
lines.append(
f"| {pkg.name} | {pkg.version} | {pkg.type} | {pkg.license_concluded or '-'} | {vuln_str} |"
)

if sbom.unique_licenses:
lines += ["", "## Licenses", ""]
Expand Down Expand Up @@ -191,7 +201,9 @@ def _parse_package(self, raw: Dict[str, Any]) -> Optional[SBOMPackage]:

return pkg

def _annotate_vulnerabilities(self, packages: List[SBOMPackage], vulns: List[Dict[str, Any]]) -> None:
def _annotate_vulnerabilities(
self, packages: List[SBOMPackage], vulns: List[Dict[str, Any]]
) -> None:
"""Map vulnerability list to packages by name."""
pkg_map = {p.name: p for p in packages}
for vuln in vulns:
Expand Down
Loading
Loading