canlix 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. canlix-0.1.0/.env.example +10 -0
  2. canlix-0.1.0/.github/workflows/canlix-scan.yml +24 -0
  3. canlix-0.1.0/.github/workflows/ci.yml +30 -0
  4. canlix-0.1.0/.gitignore +11 -0
  5. canlix-0.1.0/CLAUDE.md +107 -0
  6. canlix-0.1.0/Dockerfile +15 -0
  7. canlix-0.1.0/PKG-INFO +537 -0
  8. canlix-0.1.0/README.md +498 -0
  9. canlix-0.1.0/action.yml +70 -0
  10. canlix-0.1.0/canlix/__init__.py +1 -0
  11. canlix-0.1.0/canlix/analyzers/__init__.py +42 -0
  12. canlix-0.1.0/canlix/analyzers/deps.py +135 -0
  13. canlix-0.1.0/canlix/analyzers/python_ast.py +3300 -0
  14. canlix-0.1.0/canlix/analyzers/ts_regex.py +3492 -0
  15. canlix-0.1.0/canlix/cli.py +310 -0
  16. canlix-0.1.0/canlix/engine.py +80 -0
  17. canlix-0.1.0/canlix/models.py +107 -0
  18. canlix-0.1.0/canlix/parsers/__init__.py +19 -0
  19. canlix-0.1.0/canlix/parsers/claude.py +72 -0
  20. canlix-0.1.0/canlix/parsers/cursor.py +41 -0
  21. canlix-0.1.0/canlix/parsers/generic.py +14 -0
  22. canlix-0.1.0/canlix/parsers/vscode.py +54 -0
  23. canlix-0.1.0/canlix/probes/__init__.py +15 -0
  24. canlix-0.1.0/canlix/probes/active.py +123 -0
  25. canlix-0.1.0/canlix/probes/base.py +46 -0
  26. canlix-0.1.0/canlix/probes/metadata.py +213 -0
  27. canlix-0.1.0/canlix/probes/runner.py +44 -0
  28. canlix-0.1.0/canlix/probes/transport.py +164 -0
  29. canlix-0.1.0/canlix/reporters/__init__.py +15 -0
  30. canlix-0.1.0/canlix/reporters/json_report.py +96 -0
  31. canlix-0.1.0/canlix/reporters/sarif.py +178 -0
  32. canlix-0.1.0/canlix/reporters/terminal.py +191 -0
  33. canlix-0.1.0/canlix/rules/__init__.py +9 -0
  34. canlix-0.1.0/canlix/rules/base.py +13 -0
  35. canlix-0.1.0/canlix/rules/config.py +82 -0
  36. canlix-0.1.0/canlix/rules/cross_server.py +235 -0
  37. canlix-0.1.0/canlix/rules/execution.py +115 -0
  38. canlix-0.1.0/canlix/rules/network.py +140 -0
  39. canlix-0.1.0/canlix/rules/permissions.py +81 -0
  40. canlix-0.1.0/canlix/rules/secrets.py +108 -0
  41. canlix-0.1.0/canlix/runtime/__init__.py +6 -0
  42. canlix-0.1.0/canlix/runtime/detectors.py +290 -0
  43. canlix-0.1.0/canlix/runtime/proxy.py +170 -0
  44. canlix-0.1.0/canlix/runtime/redact.py +55 -0
  45. canlix-0.1.0/canlix/runtime/sse_server.py +159 -0
  46. canlix-0.1.0/canlix/saas_client.py +61 -0
  47. canlix-0.1.0/docker-compose.yml +14 -0
  48. canlix-0.1.0/docs/adr/0001-saas-architecture.md +71 -0
  49. canlix-0.1.0/pyproject.toml +65 -0
  50. canlix-0.1.0/saas/__init__.py +1 -0
  51. canlix-0.1.0/saas/app.py +578 -0
  52. canlix-0.1.0/saas/auth.py +42 -0
  53. canlix-0.1.0/saas/diff.py +25 -0
  54. canlix-0.1.0/saas/ingest.py +101 -0
  55. canlix-0.1.0/saas/integrations.py +172 -0
  56. canlix-0.1.0/saas/migrate.py +168 -0
  57. canlix-0.1.0/saas/pg_store.py +447 -0
  58. canlix-0.1.0/saas/portal.html +537 -0
  59. canlix-0.1.0/saas/report.py +167 -0
  60. canlix-0.1.0/saas/security.py +28 -0
  61. canlix-0.1.0/saas/store.py +265 -0
  62. canlix-0.1.0/tests/__init__.py +0 -0
  63. canlix-0.1.0/tests/fixtures/clean_config.json +17 -0
  64. canlix-0.1.0/tests/fixtures/deps/package_risky.json +13 -0
  65. canlix-0.1.0/tests/fixtures/deps/package_safe.json +13 -0
  66. canlix-0.1.0/tests/fixtures/deps/requirements_pinned.txt +6 -0
  67. canlix-0.1.0/tests/fixtures/deps/requirements_unpinned.txt +7 -0
  68. canlix-0.1.0/tests/fixtures/fake_mcp_server.py +26 -0
  69. canlix-0.1.0/tests/fixtures/source/clean_server.py +23 -0
  70. canlix-0.1.0/tests/fixtures/source/clean_server.ts +49 -0
  71. canlix-0.1.0/tests/fixtures/source/vulnerable_server.py +1067 -0
  72. canlix-0.1.0/tests/fixtures/source/vulnerable_server.ts +895 -0
  73. canlix-0.1.0/tests/fixtures/vulnerable_config.json +31 -0
  74. canlix-0.1.0/tests/integration/__init__.py +0 -0
  75. canlix-0.1.0/tests/integration/test_pg_store.py +369 -0
  76. canlix-0.1.0/tests/test_analyzers.py +3292 -0
  77. canlix-0.1.0/tests/test_cross_server.py +98 -0
  78. canlix-0.1.0/tests/test_deps_analyzer.py +203 -0
  79. canlix-0.1.0/tests/test_integrations.py +236 -0
  80. canlix-0.1.0/tests/test_probes.py +373 -0
  81. canlix-0.1.0/tests/test_push.py +182 -0
  82. canlix-0.1.0/tests/test_report.py +99 -0
  83. canlix-0.1.0/tests/test_rules.py +266 -0
  84. canlix-0.1.0/tests/test_runtime.py +240 -0
  85. canlix-0.1.0/tests/test_saas_core.py +299 -0
  86. canlix-0.1.0/tests/test_saas_http.py +621 -0
  87. canlix-0.1.0/tests/test_sarif.py +220 -0
  88. canlix-0.1.0/tests/test_sse.py +373 -0
  89. canlix-0.1.0/tests/test_ts_analyzer.py +3316 -0
@@ -0,0 +1,10 @@
1
+ # Canlix SaaS — environment variables
2
+ # Copy to .env and fill in values before running.
3
+
4
+ # PostgreSQL connection string.
5
+ # Leave unset to use the in-memory store (unit tests, local CLI).
6
+ CANLIX_DATABASE_URL=postgresql://canlix:canlix@localhost:5435/canlix
7
+
8
+ # Trust X-Forwarded-For from reverse proxy (Caddy, nginx).
9
+ # Set to 1 only when the proxy unconditionally overwrites XFF before forwarding.
10
+ CANLIX_TRUST_PROXY=0
@@ -0,0 +1,24 @@
1
+ name: Canlix self-scan
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "0 6 * * 1"
9
+
10
+ permissions:
11
+ contents: read
12
+ security-events: write
13
+
14
+ jobs:
15
+ scan:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Scan the Canlix source with Canlix
21
+ uses: ./
22
+ with:
23
+ path: canlix
24
+ fail-on: CRITICAL
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master, dev]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.10", "3.11", "3.12"]
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python ${{ matrix.python-version }}
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install
24
+ run: pip install -e ".[dev]"
25
+
26
+ - name: Lint
27
+ run: ruff check . && ruff format --check .
28
+
29
+ - name: Test
30
+ run: pytest tests/ -v --tb=short
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .env
11
+ *.db
canlix-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,107 @@
1
+ # CLAUDE.md — Canlix
2
+
3
+ Scanner de sécurité open source pour serveurs MCP et agents IA. Analyse statique (CFG/SRC), tests actifs (XSV), runtime (RUN), avec une couche SaaS multi-tenant optionnelle.
4
+
5
+ Langue de travail : français. Code, identifiants, commits, commentaires : anglais.
6
+
7
+ ## 0. Protocole de session
8
+
9
+ 1. Lire ce fichier, identifier la première tâche non cochée dans la section 7.
10
+ 2. Annoncer en trois lignes : tâche, plan, sous-agents utilisés. Exécuter sans redemander.
11
+ 3. Fin de tâche : tests passants, `py_compile` OK, `ruff check/format` propre, cocher `[x]` avec date et note.
12
+ 4. Commit systématique après chaque tâche complète.
13
+ 5. Fin de session : résumé six points (✅ Fait, ⏭ Suivant, 🔴 Bloqué, ❓ Décisions, 📝 À retenir, 📋 Proposals).
14
+
15
+ ## 1. Commandes
16
+
17
+ Répertoire : `/home/kali/mcpprobe/`
18
+
19
+ | Commande | Description |
20
+ |---|---|
21
+ | `python -m pytest tests/ --ignore=tests/integration -q` | Tests unitaires (sans DB) |
22
+ | `CANLIX_DATABASE_URL=... pytest tests/integration/ -v` | Tests d'intégration PgStore |
23
+ | `.venv/bin/ruff check . && .venv/bin/ruff format --check .` | Lint |
24
+ | `python -m saas.migrate` | Appliquer les migrations PostgreSQL |
25
+ | `uvicorn saas.app:app --reload` | Démarrer le SaaS (port 8000) |
26
+ | `docker compose up -d db` | PostgreSQL local (port 5435) |
27
+ | `canlix scan <path>` | Scan statique CLI |
28
+ | `canlix watch --http 7700` | Runtime proxy + SSE |
29
+
30
+ ## 2. Architecture
31
+
32
+ Monolithe modulaire. Pas de microservices.
33
+
34
+ ```
35
+ canlix/ CLI et règles (CFG, SRC, XSV, RUN)
36
+ saas/ Couche SaaS FastAPI
37
+ app.py Routes HTTP (20+ endpoints)
38
+ store.py Store in-memory (tests unitaires)
39
+ pg_store.py Store PostgreSQL (production)
40
+ migrate.py Migrations idempotentes (0001-0004)
41
+ integrations.py Slack / PagerDuty / Jira dispatch
42
+ report.py Rapport HTML auto-suffisant
43
+ portal.html Dashboard web (login, projets, scans, intégrations)
44
+ auth.py scrypt email/password
45
+ security.py Tokens SHA-256 cnx_*
46
+ tests/
47
+ test_saas_http.py Tests HTTP (client FastAPI)
48
+ test_saas_core.py Tests Store in-memory
49
+ test_integrations.py Tests dispatch + Store CRUD
50
+ test_report.py Tests rendu HTML
51
+ integration/
52
+ test_pg_store.py Tests PgStore PostgreSQL (skip sans DB)
53
+ docs/adr/
54
+ 0001-saas-architecture.md
55
+ ```
56
+
57
+ ## 3. Stack
58
+
59
+ - **CLI** : Python pur, zéro dépendance externe obligatoire
60
+ - **SaaS** : FastAPI + psycopg[binary,pool] + pydantic v2
61
+ - **DB** : PostgreSQL 16 + RLS (org_id sur projects/scans/findings/integrations)
62
+ - **Auth** : scrypt stdlib (email/password) + tokens SHA-256 256 bits
63
+ - **Dispatch** : urllib.request stdlib, threads daemon, timeout 8s — aucune dépendance réseau externe
64
+
65
+ ## 4. Sécurité — règles non négociables
66
+
67
+ - `org_id` dérivé du jeton, jamais lu dans le corps ou l'URL
68
+ - Ressource d'un autre tenant → 404, pas 403
69
+ - `Integration.config` (webhook URLs, routing keys, tokens) : jamais loggué, jamais retourné dans les réponses API (`IntegrationOut` omet `config`)
70
+ - Clés et secrets : variables d'environnement, jamais commités
71
+ - Tout code d'authentification ou de crypto : relu par `security-reviewer` avant fusion
72
+
73
+ ## 5. Variables d'environnement
74
+
75
+ | Variable | Description |
76
+ |---|---|
77
+ | `CANLIX_DATABASE_URL` | URL PostgreSQL (optionnel — in-memory sans ça) |
78
+ | `CANLIX_SAAS_TOKEN_TTL_DAYS` | TTL des jetons (optionnel) |
79
+
80
+ ## 6. État au 2026-11-12
81
+
82
+ - **1237 tests unitaires** passants · **24 tests PgStore** (skip sans `CANLIX_DATABASE_URL`)
83
+ - Ruff propre · HEAD `aa4d73c` sur `github.com/robkira01-max/canlix`
84
+ - Migration en prod : `python -m saas.migrate` à relancer après chaque déploiement
85
+
86
+ Livrables présents :
87
+ - Règles : CFG/SRC (config + source), XSV-001..004 (inter-serveurs), RUN-001..007 (runtime)
88
+ - Runtime Analyzer : proxy stdio, `canlix watch` / `canlix replay` / `canlix watch --http PORT`
89
+ - Action GitHub composite `action.yml` (SARIF) + workflow d'auto-scan
90
+ - SaaS HTTP : `/orgs`, `/auth/register`, `/auth/login`, `/portal`, `/orgs/me/integrations` (CRUD), `/projects/{id}/scans/{id}/report`
91
+ - Portal web : dashboard complet (token, projets, scans, intégrations Slack/PD/Jira, liens rapports)
92
+ - Migration 0004 : table `integrations` (config JSONB, isolation org)
93
+ - PgStore : parité complète avec Store in-memory + dispatch alertes sur `add_scan`
94
+
95
+ ## 7. Tâches
96
+
97
+ ### Backlog technique
98
+ - [x] **T-TM** 2026-11-12 — Vérification marque CIPO/USPTO/EUIPO toutes classes : 0 résultat. Publiable sur PyPI.
99
+
100
+ ### Backlog business
101
+ - [ ] **M9** — Pilotes commerciaux : contacter 2-3 équipes sécurité, valider tarifs 29-99 USD/mois (hors code)
102
+
103
+ ### Proposals (hors plan actuel)
104
+ - Portal : onglet « Membres » pour inviter des collègues (multi-utilisateur par org)
105
+ - CLI : `canlix ci` pour détecter automatiquement le runner CI et générer la config
106
+ - SaaS : endpoints d'administration (stats globales, désactivation d'org)
107
+ - Webhooks entrants : recevoir les résultats de scan depuis GitHub Actions directement
@@ -0,0 +1,15 @@
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
6
+
7
+ COPY pyproject.toml README.md ./
8
+ COPY canlix/ canlix/
9
+ COPY saas/ saas/
10
+
11
+ RUN pip install --no-cache-dir ".[saas]"
12
+
13
+ USER appuser
14
+
15
+ CMD ["uvicorn", "saas.app:app", "--host", "0.0.0.0", "--port", "8000"]