archsight 0.1.4 → 0.2.0
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.
- checksums.yaml +4 -4
- data/Dockerfile +5 -4
- data/README.md +44 -59
- data/chart/archsight/Chart.yaml +6 -0
- data/chart/archsight/README.md +3 -0
- data/chart/archsight/templates/NOTES.txt +22 -0
- data/chart/archsight/templates/_helpers.tpl +62 -0
- data/chart/archsight/templates/deployment.yaml +114 -0
- data/chart/archsight/templates/ingress.yaml +56 -0
- data/chart/archsight/templates/resources-configmap.yaml +10 -0
- data/chart/archsight/templates/resources-pvc.yaml +23 -0
- data/chart/archsight/templates/service.yaml +15 -0
- data/chart/archsight/templates/serviceaccount.yaml +12 -0
- data/chart/archsight/values.yaml +162 -0
- data/docs/architecture.md +39 -0
- data/docs/docker.md +49 -0
- data/{lib/archsight/web/doc → docs}/import.md +10 -2
- data/{lib/archsight/web/doc → docs}/index.md.erb +3 -1
- data/docs/kubernetes.md +149 -0
- data/docs/licenses.md +307 -0
- data/lib/archsight/analysis/executor.rb +0 -10
- data/lib/archsight/annotations/annotation.rb +85 -36
- data/lib/archsight/annotations/architecture_annotations.rb +1 -34
- data/lib/archsight/annotations/computed.rb +1 -1
- data/lib/archsight/annotations/generated_annotations.rb +6 -3
- data/lib/archsight/annotations/git_annotations.rb +8 -4
- data/lib/archsight/annotations/interface_annotations.rb +35 -0
- data/lib/archsight/cli.rb +4 -2
- data/lib/archsight/editor/content_hasher.rb +37 -0
- data/lib/archsight/editor/file_writer.rb +79 -0
- data/lib/archsight/editor.rb +237 -0
- data/lib/archsight/graph.rb +1 -51
- data/lib/archsight/helpers.rb +0 -20
- data/lib/archsight/import/handlers/github.rb +16 -6
- data/lib/archsight/import/handlers/gitlab.rb +28 -10
- data/lib/archsight/import/handlers/repository.rb +56 -6
- data/lib/archsight/import/handlers/rest_api.rb +13 -1
- data/lib/archsight/import/license_analyzer.rb +650 -0
- data/lib/archsight/import/team_matcher.rb +111 -61
- data/lib/archsight/linter.rb +1 -1
- data/lib/archsight/mcp/base.rb +11 -0
- data/lib/archsight/mcp/execute_analysis_tool.rb +100 -0
- data/lib/archsight/mcp.rb +1 -0
- data/lib/archsight/renderer.rb +4 -4
- data/lib/archsight/resources/analysis.rb +1 -17
- data/lib/archsight/resources/application_interface.rb +1 -5
- data/lib/archsight/resources/base.rb +14 -14
- data/lib/archsight/resources/business_actor.rb +18 -3
- data/lib/archsight/resources/technology_artifact.rb +48 -0
- data/lib/archsight/resources/technology_interface.rb +1 -1
- data/lib/archsight/resources/technology_service.rb +5 -0
- data/lib/archsight/version.rb +1 -1
- data/lib/archsight/web/api/docs.rb +37 -2
- data/lib/archsight/web/api/json_helpers.rb +79 -13
- data/lib/archsight/web/api/openapi/spec.yaml +699 -0
- data/lib/archsight/web/api/routes.rb +23 -0
- data/lib/archsight/web/application.rb +48 -128
- data/lib/archsight/web/editor/form_builder.rb +100 -0
- data/lib/archsight/web/editor/helpers.rb +150 -0
- data/lib/archsight/web/editor/routes.rb +166 -0
- data/lib/archsight/web/public/vue/ApiDocsPage-B1RqTNqh.js +1 -0
- data/lib/archsight/web/public/vue/ApiDocsPage-DhNTOH4o.css +1 -0
- data/lib/archsight/web/public/vue/DocPage-DzwBgBd4.js +1 -0
- data/lib/archsight/web/public/vue/EditorPage-D_miHSv4.js +34 -0
- data/lib/archsight/web/public/vue/EditorPage-Dq0MuTnp.css +1 -0
- data/lib/archsight/web/public/vue/ErrorPage-CQQtPey3.js +2 -0
- data/lib/archsight/web/public/vue/ErrorPage-CwPT3JUr.css +1 -0
- data/lib/archsight/web/public/vue/GraphView-DRcIqAiR.css +1 -0
- data/lib/archsight/web/public/vue/GraphView-T9jFH_qg.js +1 -0
- data/lib/archsight/web/public/vue/InstanceRouter-1Sm-CRhf.js +2 -0
- data/lib/archsight/web/public/vue/InstanceRouter-BJkDRXZY.css +1 -0
- data/lib/archsight/web/public/vue/KindList-JA_L_-Cz.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-8iqavWdg.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-DP-z-j71.css +1 -0
- data/lib/archsight/web/public/vue/SearchResults-BGHbg48-.css +1 -0
- data/lib/archsight/web/public/vue/SearchResults-BdgFeHcm.js +1 -0
- data/lib/archsight/web/public/vue/_basePickBy-CVgieyx-.js +1 -0
- data/lib/archsight/web/public/vue/_baseUniq-BNfrOSaP.js +1 -0
- data/lib/archsight/web/public/vue/architectureDiagram-VXUJARFQ-CJXNpTr5.js +36 -0
- data/lib/archsight/web/public/vue/blockDiagram-VD42YOAC-B5488Hes.js +122 -0
- data/lib/archsight/web/public/vue/c4Diagram-YG6GDRKO-eYY3hprM.js +10 -0
- data/lib/archsight/web/public/vue/chunk-4BX2VUAB-ZoXeL4D1.js +1 -0
- data/lib/archsight/web/public/vue/chunk-55IACEB6-rNtQYnu_.js +1 -0
- data/lib/archsight/web/public/vue/chunk-B4BG7PRW-DolAeVV9.js +165 -0
- data/lib/archsight/web/public/vue/chunk-DI55MBZ5-DnN0f_hj.js +220 -0
- data/lib/archsight/web/public/vue/chunk-FMBD7UC4-BQWOCMuR.js +15 -0
- data/lib/archsight/web/public/vue/chunk-QN33PNHL-DId301Kb.js +1 -0
- data/lib/archsight/web/public/vue/chunk-QZHKN3VN-xbY0NLgv.js +1 -0
- data/lib/archsight/web/public/vue/chunk-TZMSLE5B-CgF9_37b.js +1 -0
- data/lib/archsight/web/public/vue/classDiagram-2ON5EDUG-jGlvI-Za.js +1 -0
- data/lib/archsight/web/public/vue/classDiagram-v2-WZHVMYZB-jGlvI-Za.js +1 -0
- data/lib/archsight/web/public/vue/clone-6iRPe1-W.js +1 -0
- data/lib/archsight/web/public/vue/cose-bilkent-S5V4N54A-CB9Zfu50.js +1 -0
- data/lib/archsight/web/public/vue/cytoscape.esm-5J0xJHOV.js +321 -0
- data/lib/archsight/web/public/vue/dagre-6UL2VRFP-BqkmE-LI.js +4 -0
- data/lib/archsight/web/public/vue/diagram-PSM6KHXK-CKBfqtw3.js +24 -0
- data/lib/archsight/web/public/vue/diagram-QEK2KX5R-B78rOlvK.js +43 -0
- data/lib/archsight/web/public/vue/diagram-S2PKOQOG-BlXC6Cia.js +24 -0
- data/lib/archsight/web/public/vue/erDiagram-Q2GNP2WA-BnliyziJ.js +60 -0
- data/lib/archsight/web/public/vue/flowDiagram-NV44I4VS-wuqPowTd.js +162 -0
- data/lib/archsight/web/public/vue/ganttDiagram-JELNMOA3-GSffAIH3.js +267 -0
- data/lib/archsight/web/public/vue/gitGraphDiagram-V2S2FVAM-OA7VyugW.js +65 -0
- data/lib/archsight/web/public/vue/graph-BXHAtA0S.js +1 -0
- data/lib/archsight/web/public/vue/graphviz-CJms5bxZ.js +13 -0
- data/lib/archsight/web/public/vue/index-DsEsN0_K.js +2 -0
- data/lib/archsight/web/public/vue/index-Tiu4C-Sb.css +1 -0
- data/lib/archsight/web/public/vue/infoDiagram-HS3SLOUP-nlVe2qgv.js +2 -0
- data/lib/archsight/web/public/vue/journeyDiagram-XKPGCS4Q-CtTIcKwf.js +139 -0
- data/lib/archsight/web/public/vue/kanban-definition-3W4ZIXB7-837KX0sW.js +89 -0
- data/lib/archsight/web/public/vue/katex-C-M49wc6.js +261 -0
- data/lib/archsight/web/public/vue/layout-DtE0QdL6.js +1 -0
- data/lib/archsight/web/public/vue/mermaid-DpPHPFQh.js +250 -0
- data/lib/archsight/web/public/vue/mindmap-definition-VGOIOE7T-9gLF2AoY.js +68 -0
- data/lib/archsight/web/public/vue/pieDiagram-ADFJNKIX-CyCNgw3u.js +30 -0
- data/lib/archsight/web/public/vue/quadrantDiagram-AYHSOK5B-CkPh8g02.js +7 -0
- data/lib/archsight/web/public/vue/requirementDiagram-UZGBJVZJ-Dkt6OSlY.js +64 -0
- data/lib/archsight/web/public/vue/sankeyDiagram-TZEHDZUN-BqprTk8x.js +10 -0
- data/lib/archsight/web/public/vue/sequenceDiagram-WL72ISMW-CTmTe1FQ.js +145 -0
- data/lib/archsight/web/public/vue/stateDiagram-FKZM4ZOC-CphqmkEU.js +1 -0
- data/lib/archsight/web/public/vue/stateDiagram-v2-4FDKWEC3-CxaDW5sW.js +1 -0
- data/lib/archsight/web/public/vue/timeline-definition-IT6M3QCI-CSQUZkyE.js +61 -0
- data/lib/archsight/web/public/vue/treemap-GDKQZRPO-DTojm7Yr.js +162 -0
- data/lib/archsight/web/public/{css/graph.css → vue/useGraphviz-A5s4h76R.js} +2 -1
- data/lib/archsight/web/public/vue/useHighlight-C6Kb5G3l.js +10 -0
- data/lib/archsight/web/public/vue/useMermaid-DqxTrLRB.js +1 -0
- data/lib/archsight/web/public/vue/usePanZoom-BybZ_rfh.js +11 -0
- data/lib/archsight/web/public/vue/xychartDiagram-PRI3JC2R-B1ZJZtDC.js +7 -0
- data/lib/archsight/web/public/vue.html +15 -0
- data/media/artifact.jpg +0 -0
- data/media/service.jpg +0 -0
- metadata +104 -77
- data/lib/archsight/web/public/css/artifact.css +0 -995
- data/lib/archsight/web/public/css/base.css +0 -201
- data/lib/archsight/web/public/css/highlight.min.css +0 -10
- data/lib/archsight/web/public/css/iconoir.css +0 -22
- data/lib/archsight/web/public/css/instance.css +0 -818
- data/lib/archsight/web/public/css/layout.css +0 -421
- data/lib/archsight/web/public/css/mermaid-layers.css +0 -188
- data/lib/archsight/web/public/css/pico.min.css +0 -4
- data/lib/archsight/web/public/img/archimate.png +0 -0
- data/lib/archsight/web/public/img/togaf-high-level.png +0 -0
- data/lib/archsight/web/public/js/graph-zoom.js +0 -18
- data/lib/archsight/web/public/js/highlight.min.js +0 -3899
- data/lib/archsight/web/public/js/htmx.min.js +0 -1
- data/lib/archsight/web/public/js/mermaid-init.js +0 -88
- data/lib/archsight/web/public/js/mermaid.min.js +0 -2811
- data/lib/archsight/web/public/js/sparkline.js +0 -42
- data/lib/archsight/web/public/js/svg-pan-zoom.min.js +0 -3
- data/lib/archsight/web/public/js/svg-zoom-controls.js +0 -93
- data/lib/archsight/web/views/api_docs.erb +0 -19
- data/lib/archsight/web/views/index.haml +0 -12
- data/lib/archsight/web/views/partials/artifact/_activity.haml +0 -55
- data/lib/archsight/web/views/partials/artifact/_agentic.haml +0 -25
- data/lib/archsight/web/views/partials/artifact/_deployment.haml +0 -29
- data/lib/archsight/web/views/partials/artifact/_git_info.haml +0 -16
- data/lib/archsight/web/views/partials/artifact/_language_stats.haml +0 -53
- data/lib/archsight/web/views/partials/artifact/_links.haml +0 -24
- data/lib/archsight/web/views/partials/artifact/_project_estimate.haml +0 -32
- data/lib/archsight/web/views/partials/artifact/_repositories.haml +0 -55
- data/lib/archsight/web/views/partials/artifact/_team.haml +0 -83
- data/lib/archsight/web/views/partials/artifact/_workflow.haml +0 -69
- data/lib/archsight/web/views/partials/components/_activity.haml +0 -37
- data/lib/archsight/web/views/partials/components/_git.haml +0 -17
- data/lib/archsight/web/views/partials/components/_jira.haml +0 -18
- data/lib/archsight/web/views/partials/components/_languages.haml +0 -29
- data/lib/archsight/web/views/partials/components/_owner.haml +0 -15
- data/lib/archsight/web/views/partials/components/_repositories.haml +0 -37
- data/lib/archsight/web/views/partials/components/_status.haml +0 -23
- data/lib/archsight/web/views/partials/instance/_analysis_detail.haml +0 -74
- data/lib/archsight/web/views/partials/instance/_analysis_result.haml +0 -64
- data/lib/archsight/web/views/partials/instance/_detail.haml +0 -103
- data/lib/archsight/web/views/partials/instance/_graph.haml +0 -6
- data/lib/archsight/web/views/partials/instance/_import_detail.haml +0 -87
- data/lib/archsight/web/views/partials/instance/_list.haml +0 -84
- data/lib/archsight/web/views/partials/instance/_relations.haml +0 -43
- data/lib/archsight/web/views/partials/instance/_requirements.haml +0 -41
- data/lib/archsight/web/views/partials/instance/_view_detail.haml +0 -57
- data/lib/archsight/web/views/partials/layout/_content.haml +0 -44
- data/lib/archsight/web/views/partials/layout/_error.haml +0 -22
- data/lib/archsight/web/views/partials/layout/_head.haml +0 -24
- data/lib/archsight/web/views/partials/layout/_navigation.haml +0 -21
- data/lib/archsight/web/views/partials/layout/_sidebar.haml +0 -27
- data/lib/archsight/web/views/search.haml +0 -53
- /data/{lib/archsight/web/doc → docs}/archimate.md +0 -0
- /data/{lib/archsight/web/doc → docs}/computed_annotations.md +0 -0
- /data/{lib/archsight/web/doc → docs}/icons.md +0 -0
- /data/{lib/archsight/web/doc → docs}/modeling.md +0 -0
- /data/{lib/archsight/web/doc → docs}/search.md +0 -0
- /data/{lib/archsight/web/doc → docs}/togaf.md +0 -0
- /data/{lib/archsight/web/doc → docs}/tool.md +0 -0
data/docs/licenses.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# License Scanning
|
|
2
|
+
|
|
3
|
+
The repository import automatically detects and analyzes software licenses for each imported repository. This produces a "Layer 1 Licensing Profile" that characterizes license usage across your portfolio.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
When the `repository` handler imports a git repository, it runs license analysis alongside code metrics and git history analysis. The license analyzer:
|
|
8
|
+
|
|
9
|
+
1. **Detects the repository's own license** from LICENSE/COPYING files, SPDX headers, and package manifests
|
|
10
|
+
2. **Scans dependency licenses** using language-specific tools (when available) or falls back to manifest-based counting
|
|
11
|
+
3. **Classifies risk** based on copyleft presence and unknown license ratios
|
|
12
|
+
|
|
13
|
+
Results are stored as `license/*` annotations on the TechnologyArtifact resource.
|
|
14
|
+
|
|
15
|
+
## How License Detection Works
|
|
16
|
+
|
|
17
|
+
The analyzer uses a priority-based detection strategy:
|
|
18
|
+
|
|
19
|
+
### 1. SPDX-License-Identifier Headers (highest priority)
|
|
20
|
+
|
|
21
|
+
Source files are scanned for standardized SPDX headers:
|
|
22
|
+
|
|
23
|
+
```go
|
|
24
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
25
|
+
package main
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This is the most reliable signal and takes priority over all other methods.
|
|
29
|
+
|
|
30
|
+
### 2. LICENSE / COPYING Files
|
|
31
|
+
|
|
32
|
+
The analyzer searches for these files in the repository root (in order):
|
|
33
|
+
|
|
34
|
+
- `LICENSE`, `LICENSE.md`, `LICENSE.txt`
|
|
35
|
+
- `LICENCE`, `LICENCE.md`, `LICENCE.txt`
|
|
36
|
+
- `COPYING`, `COPYING.md`, `COPYING.txt`
|
|
37
|
+
|
|
38
|
+
File content is matched against known license patterns for:
|
|
39
|
+
|
|
40
|
+
| License | Category |
|
|
41
|
+
|---------|----------|
|
|
42
|
+
| Apache-2.0 | permissive |
|
|
43
|
+
| MIT | permissive |
|
|
44
|
+
| BSD-3-Clause, BSD-2-Clause | permissive |
|
|
45
|
+
| ISC | permissive |
|
|
46
|
+
| Unlicense, CC0-1.0, BSL-1.0 | permissive |
|
|
47
|
+
| GPL-3.0, GPL-2.0, AGPL-3.0 | copyleft |
|
|
48
|
+
| LGPL-3.0, LGPL-2.1 | weak-copyleft |
|
|
49
|
+
| MPL-2.0, EUPL-1.2 | weak-copyleft |
|
|
50
|
+
|
|
51
|
+
### 3. Package Manifest Fallback (lowest priority)
|
|
52
|
+
|
|
53
|
+
If no LICENSE file is found, the analyzer checks manifest files:
|
|
54
|
+
|
|
55
|
+
- `package.json` `"license"` field (Node.js)
|
|
56
|
+
- `*.gemspec` `spec.license` (Ruby)
|
|
57
|
+
- `Cargo.toml` `license` key (Rust)
|
|
58
|
+
- `pyproject.toml` `license` key (Python)
|
|
59
|
+
|
|
60
|
+
## Dependency License Scanning
|
|
61
|
+
|
|
62
|
+
### Supported Ecosystems
|
|
63
|
+
|
|
64
|
+
The analyzer detects ecosystems from manifest files and attempts to scan dependencies:
|
|
65
|
+
|
|
66
|
+
| Ecosystem | Detected By | External Tool | Fallback |
|
|
67
|
+
|-----------|-------------|---------------|----------|
|
|
68
|
+
| Go | `go.mod` | `go-licenses` | Count `go.sum` entries |
|
|
69
|
+
| Python | `requirements.txt`, `pyproject.toml`, `Pipfile` | `pip-licenses` | Count requirements entries |
|
|
70
|
+
| Ruby | `Gemfile`, `Gemfile.lock` | `license_finder` | Count lockfile entries |
|
|
71
|
+
| Java | `pom.xml`, `build.gradle` | Maven license plugin | Count `<dependency>` blocks |
|
|
72
|
+
| Node.js | `package.json` | `license-checker` | Count dependency keys |
|
|
73
|
+
| Rust | `Cargo.toml` | `cargo-license` | Count `Cargo.lock` packages |
|
|
74
|
+
|
|
75
|
+
### External Tools (Soft Dependencies)
|
|
76
|
+
|
|
77
|
+
When external tools are available, they provide per-dependency license identification. The analyzer tries multiple command variants for each ecosystem and falls back gracefully:
|
|
78
|
+
|
|
79
|
+
| Ecosystem | Direct command | Runner fallback |
|
|
80
|
+
|-----------|---------------|-----------------|
|
|
81
|
+
| Go | `go-licenses` | — |
|
|
82
|
+
| Python | `pip-licenses` | `python -m piplicenses` / `python3 -m piplicenses` |
|
|
83
|
+
| Ruby | `license_finder` | `gem exec license_finder` |
|
|
84
|
+
| Node.js | `license-checker` | — |
|
|
85
|
+
| Rust | `cargo-license` | `cargo license` |
|
|
86
|
+
|
|
87
|
+
For Python projects, the analyzer also checks for `pip-licenses` inside `.venv/` or `venv/` virtual environments before trying system commands.
|
|
88
|
+
|
|
89
|
+
If no tool is available, the analyzer falls back to counting dependencies from lockfiles and manifests. These dependencies are recorded with an "unknown" license type.
|
|
90
|
+
|
|
91
|
+
### Performance
|
|
92
|
+
|
|
93
|
+
The license analyzer is optimized for batch imports of many repositories:
|
|
94
|
+
|
|
95
|
+
- **Command caching**: The first repository probes which tool variant works for each ecosystem. All subsequent repositories reuse the cached result instantly — no repeated failed process spawns.
|
|
96
|
+
- **No download-on-demand**: Runners like `npx --yes` or `go run ...@latest` that download/compile tools are not used, as they add 10-30s per repo. Install tools globally instead.
|
|
97
|
+
- **Parallel execution**: License analysis and team matching run concurrently in the repository handler.
|
|
98
|
+
- **Fast fallback**: When no external tool is found, manifest-based dependency counting is near-instant (file reads only).
|
|
99
|
+
|
|
100
|
+
To get the best results, pre-install tools globally:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
go install github.com/google/go-licenses@latest # Go
|
|
104
|
+
pip install pip-licenses # Python
|
|
105
|
+
gem install license_finder # Ruby
|
|
106
|
+
npm install -g license-checker # Node.js
|
|
107
|
+
cargo install cargo-license # Rust
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Risk Classification
|
|
111
|
+
|
|
112
|
+
Dependency risk is assessed based on detected license types:
|
|
113
|
+
|
|
114
|
+
| Risk Level | Criteria |
|
|
115
|
+
|------------|----------|
|
|
116
|
+
| **low** | All dependency licenses are permissive |
|
|
117
|
+
| **medium** | Weak-copyleft licenses present (LGPL, MPL, EUPL) but no strong copyleft |
|
|
118
|
+
| **high** | Strong copyleft (GPL, AGPL) present, or majority of licenses are unknown |
|
|
119
|
+
| **unknown** | No dependency license data available |
|
|
120
|
+
|
|
121
|
+
## License Normalization
|
|
122
|
+
|
|
123
|
+
Dependency tools return messy license strings — copyright notices, long-form names, leading parentheses, dual licenses, and domain names. The analyzer normalizes these into canonical SPDX identifiers in five phases:
|
|
124
|
+
|
|
125
|
+
### 1. Proprietary Detection
|
|
126
|
+
|
|
127
|
+
Before any cleanup, the raw string is checked for proprietary markers. If matched, the result is `proprietary`:
|
|
128
|
+
|
|
129
|
+
| Pattern | Examples |
|
|
130
|
+
|---------|----------|
|
|
131
|
+
| Copyright notice | `Copyright (C) 2024 Acme Corp`, `(c) 1&1 IONOS Cloud GmbH` |
|
|
132
|
+
| Proprietary keyword | `Proprietary License`, `UNLICENSED` |
|
|
133
|
+
| Internal marker | `IONOS internal`, `internal` |
|
|
134
|
+
| Custom URL prefix | `Custom: https://example.com/license` |
|
|
135
|
+
| Domain-as-license | `ionos.com`, `profitbricks.com`, `example.io` |
|
|
136
|
+
|
|
137
|
+
### 2. Clean
|
|
138
|
+
|
|
139
|
+
Strip leading `("(`, trailing `,;)"*`, and surrounding whitespace. This handles messy tool output like `"MIT`, `(GPL-2.0`, `Apache*`.
|
|
140
|
+
|
|
141
|
+
### 3. Dual License Split
|
|
142
|
+
|
|
143
|
+
If the string contains `/` or ` OR `, it is split and the first recognized SPDX ID is returned:
|
|
144
|
+
|
|
145
|
+
| Input | Output |
|
|
146
|
+
|-------|--------|
|
|
147
|
+
| `MIT/Apache-2.0` | `MIT` |
|
|
148
|
+
| `(MIT OR CC0-1.0)` | `MIT` |
|
|
149
|
+
|
|
150
|
+
### 4. Long-form Pattern Matching
|
|
151
|
+
|
|
152
|
+
Common long-form names and aliases are mapped to canonical SPDX IDs:
|
|
153
|
+
|
|
154
|
+
| Input | Output |
|
|
155
|
+
|-------|--------|
|
|
156
|
+
| `Apache License, Version 2.0` / `Apache 2.0` / `Apache` | `Apache-2.0` |
|
|
157
|
+
| `The MIT License` | `MIT` |
|
|
158
|
+
| `New BSD` | `BSD-3-Clause` |
|
|
159
|
+
| `Simplified BSD` / `BSD 2-Clause` | `BSD-2-Clause` |
|
|
160
|
+
| `0BSD` | `0BSD` |
|
|
161
|
+
| `GNU General Public License v2` / `GPLv2` | `GPL-2.0` |
|
|
162
|
+
| `GNU LGPL 3` / `GNU Lesser General Public License` | `LGPL-3.0` / `LGPL-2.1` |
|
|
163
|
+
| `CDDL + GPLv2 with classpath exception` | `CDDL-1.0` |
|
|
164
|
+
| `UNKNOWN` | `unknown` |
|
|
165
|
+
| `ruby` | `Ruby` |
|
|
166
|
+
|
|
167
|
+
### 5. Fallback
|
|
168
|
+
|
|
169
|
+
If no pattern matches, the cleaned string is returned as-is.
|
|
170
|
+
|
|
171
|
+
## Generated Annotations
|
|
172
|
+
|
|
173
|
+
The license analyzer produces these annotations on TechnologyArtifact resources:
|
|
174
|
+
|
|
175
|
+
### Repository License
|
|
176
|
+
|
|
177
|
+
| Annotation | Description | Example |
|
|
178
|
+
|------------|-------------|---------|
|
|
179
|
+
| `license/spdx` | SPDX license identifier | `Apache-2.0` |
|
|
180
|
+
| `license/file` | Detected license file name | `LICENSE` |
|
|
181
|
+
| `license/category` | License category | `permissive` |
|
|
182
|
+
|
|
183
|
+
### Dependency Licenses
|
|
184
|
+
|
|
185
|
+
| Annotation | Description | Example |
|
|
186
|
+
|------------|-------------|---------|
|
|
187
|
+
| `license/dependencies/count` | Total dependency count | `142` |
|
|
188
|
+
| `license/dependencies/ecosystems` | Detected ecosystems (comma-separated) | `go,python` |
|
|
189
|
+
| `license/dependencies/licenses` | Unique license types found | `Apache-2.0,BSD-3-Clause,MIT` |
|
|
190
|
+
| `license/dependencies/copyleft` | Whether copyleft deps exist | `false` |
|
|
191
|
+
| `license/dependencies/risk` | Overall risk level | `low` |
|
|
192
|
+
| `license/dependencies/*/count` | Per-license-type count | `license/dependencies/MIT/count: 80` |
|
|
193
|
+
|
|
194
|
+
## Querying License Data
|
|
195
|
+
|
|
196
|
+
Use the search and query system to find repositories by license characteristics:
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
# Find all repositories with copyleft licenses
|
|
200
|
+
TechnologyArtifact: license/category == "copyleft"
|
|
201
|
+
|
|
202
|
+
# Find repos with high dependency risk
|
|
203
|
+
TechnologyArtifact: license/dependencies/risk == "high"
|
|
204
|
+
|
|
205
|
+
# Find repos with copyleft dependencies
|
|
206
|
+
TechnologyArtifact: license/dependencies/copyleft == "true"
|
|
207
|
+
|
|
208
|
+
# Find repos using a specific license
|
|
209
|
+
TechnologyArtifact: license/spdx == "MIT"
|
|
210
|
+
|
|
211
|
+
# Find repos with Go dependencies
|
|
212
|
+
TechnologyArtifact: license/dependencies/ecosystems *= "go"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Aggregating License Profiles
|
|
216
|
+
|
|
217
|
+
Use [computed annotations](/doc/computed_annotations) to build a licensing profile across products or services. For example, on an ApplicationComponent that groups multiple repositories:
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
# Count repos per license category
|
|
221
|
+
computed_annotation 'computed/license_permissive_count',
|
|
222
|
+
title: 'Permissive License Repos',
|
|
223
|
+
type: Integer do
|
|
224
|
+
artifacts = outgoing_transitive('TechnologyArtifact: license/category == "permissive"')
|
|
225
|
+
count(artifacts)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Detect if any copyleft dependencies exist in the portfolio
|
|
229
|
+
computed_annotation 'computed/license_copyleft_present',
|
|
230
|
+
title: 'Copyleft Dependencies',
|
|
231
|
+
filter: :word do
|
|
232
|
+
artifacts = outgoing_transitive('TechnologyArtifact: license/dependencies/copyleft == "true"')
|
|
233
|
+
count(artifacts).positive? ? "true" : "false"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Collect all unique dependency licenses across the portfolio
|
|
237
|
+
computed_annotation 'computed/license_types',
|
|
238
|
+
title: 'All License Types',
|
|
239
|
+
filter: :list,
|
|
240
|
+
list: true do
|
|
241
|
+
collect(outgoing_transitive(:TechnologyArtifact), 'license/dependencies/licenses')
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Highest dependency risk across all repos
|
|
245
|
+
computed_annotation 'computed/license_max_risk',
|
|
246
|
+
title: 'Max License Risk',
|
|
247
|
+
filter: :word do
|
|
248
|
+
risks = collect(outgoing_transitive(:TechnologyArtifact), 'license/dependencies/risk')
|
|
249
|
+
%w[high medium low unknown].find { |r| risks.include?(r) }
|
|
250
|
+
end
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Example Output
|
|
254
|
+
|
|
255
|
+
After importing a Go repository with an Apache-2.0 license:
|
|
256
|
+
|
|
257
|
+
```yaml
|
|
258
|
+
apiVersion: architecture/v1alpha1
|
|
259
|
+
kind: TechnologyArtifact
|
|
260
|
+
metadata:
|
|
261
|
+
name: "Repo:my-service"
|
|
262
|
+
annotations:
|
|
263
|
+
artifact/type: repo
|
|
264
|
+
repository/git: git@github.com:org/my-service.git
|
|
265
|
+
license/spdx: Apache-2.0
|
|
266
|
+
license/file: LICENSE
|
|
267
|
+
license/category: permissive
|
|
268
|
+
license/dependencies/count: "87"
|
|
269
|
+
license/dependencies/ecosystems: go
|
|
270
|
+
license/dependencies/licenses: Apache-2.0,BSD-3-Clause,MIT
|
|
271
|
+
license/dependencies/copyleft: "false"
|
|
272
|
+
license/dependencies/risk: low
|
|
273
|
+
license/dependencies/MIT/count: "42"
|
|
274
|
+
license/dependencies/Apache-2.0/count: "30"
|
|
275
|
+
license/dependencies/BSD-3-Clause/count: "15"
|
|
276
|
+
spec:
|
|
277
|
+
suppliedBy:
|
|
278
|
+
technologyComponents:
|
|
279
|
+
- "Git:Github"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Web UI
|
|
283
|
+
|
|
284
|
+
License information is displayed in the TechnologyArtifact detail view with:
|
|
285
|
+
|
|
286
|
+
- A color-coded badge for the repository license (green = permissive, yellow = weak-copyleft, red = copyleft)
|
|
287
|
+
- Dependency count and ecosystem badges
|
|
288
|
+
- Risk level indicator
|
|
289
|
+
- Expandable per-license-type breakdown with counts
|
|
290
|
+
|
|
291
|
+
## Troubleshooting
|
|
292
|
+
|
|
293
|
+
### License Not Detected
|
|
294
|
+
|
|
295
|
+
If a repository shows `NOASSERTION` for its license:
|
|
296
|
+
|
|
297
|
+
1. Verify the LICENSE file exists in the repository root
|
|
298
|
+
2. Check that the license text matches a known pattern (some custom licenses won't match)
|
|
299
|
+
3. Add an SPDX header to a source file for reliable detection
|
|
300
|
+
|
|
301
|
+
### All Dependencies Show "unknown" License
|
|
302
|
+
|
|
303
|
+
This means no external scanning tool was available. The analyzer fell back to counting dependencies from manifest/lockfiles. Install the appropriate tool for the ecosystem (see [External Tools](#external-tools) above).
|
|
304
|
+
|
|
305
|
+
### High Risk Due to Unknown Licenses
|
|
306
|
+
|
|
307
|
+
A high proportion of "unknown" licenses triggers a "high" risk classification. This is by design - unknown licenses should be investigated. Install ecosystem-specific tools to resolve unknowns into actual license identifiers.
|
|
@@ -79,9 +79,6 @@ module Archsight
|
|
|
79
79
|
# Filter by name pattern if provided
|
|
80
80
|
analyses = analyses.select { |a| filter.match?(a.name) } if filter
|
|
81
81
|
|
|
82
|
-
# Filter to enabled analyses
|
|
83
|
-
analyses = analyses.select { |a| analysis_enabled?(a) }
|
|
84
|
-
|
|
85
82
|
analyses.map { |analysis| execute(analysis) }
|
|
86
83
|
end
|
|
87
84
|
|
|
@@ -100,13 +97,6 @@ module Archsight
|
|
|
100
97
|
|
|
101
98
|
DEFAULT_TIMEOUT
|
|
102
99
|
end
|
|
103
|
-
|
|
104
|
-
# Check if analysis is enabled
|
|
105
|
-
# @param analysis [Object] Analysis instance
|
|
106
|
-
# @return [Boolean] true if enabled
|
|
107
|
-
def analysis_enabled?(analysis)
|
|
108
|
-
analysis.annotations["analysis/enabled"] != "false"
|
|
109
|
-
end
|
|
110
100
|
end
|
|
111
101
|
end
|
|
112
102
|
end
|
|
@@ -4,7 +4,7 @@ require_relative "email_recipient"
|
|
|
4
4
|
|
|
5
5
|
# Annotation represents a single annotation definition with its schema and behavior
|
|
6
6
|
class Archsight::Annotations::Annotation
|
|
7
|
-
attr_reader :key, :description, :filter, :format, :enum, :sidebar, :type, :list
|
|
7
|
+
attr_reader :key, :description, :filter, :format, :enum, :sidebar, :type, :list, :editor
|
|
8
8
|
|
|
9
9
|
def initialize(key, options = {})
|
|
10
10
|
@key = key
|
|
@@ -14,6 +14,7 @@ class Archsight::Annotations::Annotation
|
|
|
14
14
|
@enum = options[:enum]
|
|
15
15
|
@sidebar = options.fetch(:sidebar, true)
|
|
16
16
|
@list = options.fetch(:list, false)
|
|
17
|
+
@editor = options.fetch(:editor, true)
|
|
17
18
|
@type = options[:type]
|
|
18
19
|
|
|
19
20
|
# Auto-add filter if enum present
|
|
@@ -80,43 +81,12 @@ class Archsight::Annotations::Annotation
|
|
|
80
81
|
|
|
81
82
|
# Validate a value and return array of error messages (empty if valid)
|
|
82
83
|
def validate(value)
|
|
83
|
-
errors = []
|
|
84
|
+
errors = [] #: Array[String]
|
|
84
85
|
return errors if value.nil?
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
if
|
|
88
|
-
|
|
89
|
-
invalid_values = values.reject { |v| @enum.include?(v) }
|
|
90
|
-
invalid_values.each do |v|
|
|
91
|
-
errors << "invalid value '#{v}'. Expected one of: #{@enum.join(", ")}"
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Check type constraint
|
|
96
|
-
if @type.is_a?(Class) && errors.empty?
|
|
97
|
-
values_to_check = list? ? value.to_s.split(/,|\n/).map(&:strip).reject(&:empty?) : [value.to_s]
|
|
98
|
-
|
|
99
|
-
values_to_check.each do |string_value|
|
|
100
|
-
valid = case @type.to_s
|
|
101
|
-
when "Integer"
|
|
102
|
-
string_value.match?(/\A-?\d+\z/)
|
|
103
|
-
when "Float"
|
|
104
|
-
string_value.match?(/\A-?\d+(\.\d+)?\z/)
|
|
105
|
-
when "URI"
|
|
106
|
-
begin
|
|
107
|
-
URI.parse(string_value)
|
|
108
|
-
string_value.match?(%r{\Ahttps?://})
|
|
109
|
-
rescue URI::InvalidURIError
|
|
110
|
-
false
|
|
111
|
-
end
|
|
112
|
-
when "Archsight::Annotations::EmailRecipient"
|
|
113
|
-
Archsight::Annotations::EmailRecipient.valid?(string_value)
|
|
114
|
-
else
|
|
115
|
-
true
|
|
116
|
-
end
|
|
117
|
-
errors << "invalid value '#{string_value}'. #{type_error_message}" unless valid
|
|
118
|
-
end
|
|
119
|
-
end
|
|
87
|
+
validate_enum(value, errors)
|
|
88
|
+
validate_type(value, errors) if errors.empty?
|
|
89
|
+
validate_code(value, errors) if errors.empty?
|
|
120
90
|
|
|
121
91
|
errors
|
|
122
92
|
end
|
|
@@ -130,6 +100,18 @@ class Archsight::Annotations::Annotation
|
|
|
130
100
|
@format == :markdown
|
|
131
101
|
end
|
|
132
102
|
|
|
103
|
+
def code?
|
|
104
|
+
@format == :ruby
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def multiline?
|
|
108
|
+
@format == :multiline
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def code_language
|
|
112
|
+
@format if code?
|
|
113
|
+
end
|
|
114
|
+
|
|
133
115
|
# Example value for templates
|
|
134
116
|
def example_value
|
|
135
117
|
if @enum
|
|
@@ -155,6 +137,49 @@ class Archsight::Annotations::Annotation
|
|
|
155
137
|
end
|
|
156
138
|
end
|
|
157
139
|
|
|
140
|
+
def validate_enum(value, errors)
|
|
141
|
+
return unless @enum
|
|
142
|
+
|
|
143
|
+
values = list? ? value.to_s.split(",").map(&:strip) : [value.to_s]
|
|
144
|
+
invalid_values = values.reject { |v| @enum.include?(v) }
|
|
145
|
+
invalid_values.each do |v|
|
|
146
|
+
errors << "invalid value '#{v}'. Expected one of: #{@enum.join(", ")}"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def validate_type(value, errors)
|
|
151
|
+
return unless @type.is_a?(Class)
|
|
152
|
+
|
|
153
|
+
values_to_check = list? ? value.to_s.split(/,|\n/).map(&:strip).reject(&:empty?) : [value.to_s]
|
|
154
|
+
values_to_check.each do |string_value|
|
|
155
|
+
errors << "invalid value '#{string_value}'. #{type_error_message}" unless valid_type_value?(string_value)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def valid_type_value?(string_value)
|
|
160
|
+
case @type.to_s
|
|
161
|
+
when "Integer" then string_value.match?(/\A-?\d+\z/)
|
|
162
|
+
when "Float" then string_value.match?(/\A-?\d+(\.\d+)?\z/)
|
|
163
|
+
when "URI" then valid_uri?(string_value)
|
|
164
|
+
when "Archsight::Annotations::EmailRecipient" then Archsight::Annotations::EmailRecipient.valid?(string_value)
|
|
165
|
+
else true
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def valid_uri?(string_value)
|
|
170
|
+
URI.parse(string_value)
|
|
171
|
+
string_value.match?(%r{\Ahttps?://})
|
|
172
|
+
rescue URI::InvalidURIError
|
|
173
|
+
false
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def validate_code(value, errors)
|
|
177
|
+
return unless code? && !value.to_s.strip.empty?
|
|
178
|
+
|
|
179
|
+
syntax_error = validate_code_syntax(value.to_s)
|
|
180
|
+
errors << syntax_error if syntax_error
|
|
181
|
+
end
|
|
182
|
+
|
|
158
183
|
def derive_format
|
|
159
184
|
case @filter
|
|
160
185
|
when :word then :tag_word
|
|
@@ -165,4 +190,28 @@ class Archsight::Annotations::Annotation
|
|
|
165
190
|
def build_regex
|
|
166
191
|
Regexp.new("^#{Regexp.escape(key).gsub('\*', ".+")}$")
|
|
167
192
|
end
|
|
193
|
+
|
|
194
|
+
# Validate code syntax based on format
|
|
195
|
+
# @param code [String] The code to validate
|
|
196
|
+
# @return [String, nil] Error message or nil if valid
|
|
197
|
+
def validate_code_syntax(code)
|
|
198
|
+
case @format
|
|
199
|
+
when :ruby
|
|
200
|
+
validate_ruby_syntax(code)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Validate Ruby syntax using RubyVM
|
|
205
|
+
# @param code [String] Ruby code to validate
|
|
206
|
+
# @return [String, nil] Error message or nil if valid
|
|
207
|
+
def validate_ruby_syntax(code)
|
|
208
|
+
# steep:ignore:start
|
|
209
|
+
RubyVM::InstructionSequence.compile(code)
|
|
210
|
+
# steep:ignore:end
|
|
211
|
+
nil
|
|
212
|
+
rescue SyntaxError => e
|
|
213
|
+
# Extract just the error message without the full backtrace
|
|
214
|
+
message = e.message.lines.first&.strip || "Syntax error"
|
|
215
|
+
"Ruby syntax error: #{message}"
|
|
216
|
+
end
|
|
168
217
|
end
|
|
@@ -9,12 +9,8 @@ module Archsight::Annotations::Architecture
|
|
|
9
9
|
annotation "architecture/abbr",
|
|
10
10
|
description: "Abbreviation or short name",
|
|
11
11
|
title: "Abbreviation"
|
|
12
|
-
annotation "architecture/evidence",
|
|
13
|
-
description: "Supporting evidence or notes",
|
|
14
|
-
title: "Evidence",
|
|
15
|
-
format: :markdown
|
|
16
12
|
annotation "architecture/description",
|
|
17
|
-
description: "Textual description of the
|
|
13
|
+
description: "Textual description of the resource",
|
|
18
14
|
title: "Description",
|
|
19
15
|
format: :markdown
|
|
20
16
|
annotation "architecture/documentation",
|
|
@@ -25,35 +21,6 @@ module Archsight::Annotations::Architecture
|
|
|
25
21
|
description: "Comma-separated tags",
|
|
26
22
|
filter: :list,
|
|
27
23
|
title: "Tags"
|
|
28
|
-
annotation "architecture/encoding",
|
|
29
|
-
description: "Data encoding format",
|
|
30
|
-
filter: :list,
|
|
31
|
-
title: "Encoding"
|
|
32
|
-
annotation "architecture/title",
|
|
33
|
-
description: "Interface title",
|
|
34
|
-
title: "Title"
|
|
35
|
-
annotation "architecture/openapi",
|
|
36
|
-
description: "OpenAPI specification version",
|
|
37
|
-
filter: :word,
|
|
38
|
-
title: "OpenAPI"
|
|
39
|
-
annotation "architecture/version",
|
|
40
|
-
description: "API or interface version",
|
|
41
|
-
filter: :word,
|
|
42
|
-
title: "Version",
|
|
43
|
-
sidebar: false
|
|
44
|
-
annotation "architecture/status",
|
|
45
|
-
description: "Lifecycle status (General-Availability, Early-Access, Development)",
|
|
46
|
-
filter: :word,
|
|
47
|
-
title: "Status"
|
|
48
|
-
annotation "architecture/visibility",
|
|
49
|
-
description: "API visibility (public, private, internal)",
|
|
50
|
-
filter: :word,
|
|
51
|
-
enum: %w[public private internal],
|
|
52
|
-
title: "Visibility"
|
|
53
|
-
annotation "architecture/applicationSets",
|
|
54
|
-
description: "Related ArgoCD ApplicationSets",
|
|
55
|
-
title: "ApplicationSets",
|
|
56
|
-
format: :markdown
|
|
57
24
|
end
|
|
58
25
|
end
|
|
59
26
|
end
|
|
@@ -212,7 +212,7 @@ class Archsight::Annotations::ComputedManager
|
|
|
212
212
|
@computing.add(cache_key)
|
|
213
213
|
begin
|
|
214
214
|
evaluator = Archsight::Annotations::ComputedEvaluator.new(instance, @database, self)
|
|
215
|
-
value = evaluator.instance_eval(&definition.block)
|
|
215
|
+
value = evaluator.instance_eval(&definition.block) # steep:ignore BlockTypeMismatch
|
|
216
216
|
|
|
217
217
|
# Apply type coercion if specified
|
|
218
218
|
value = coerce_value(value, definition.type) if definition.type
|
|
@@ -7,15 +7,18 @@ module Archsight::Annotations::Generated
|
|
|
7
7
|
annotation "generated/script",
|
|
8
8
|
description: "Name of the script that generated this resource",
|
|
9
9
|
title: "Generated By",
|
|
10
|
-
sidebar: false
|
|
10
|
+
sidebar: false,
|
|
11
|
+
editor: false
|
|
11
12
|
annotation "generated/at",
|
|
12
13
|
description: "Timestamp when this resource was generated (ISO8601)",
|
|
13
14
|
title: "Generated At",
|
|
14
|
-
sidebar: false
|
|
15
|
+
sidebar: false,
|
|
16
|
+
editor: false
|
|
15
17
|
annotation "generated/configHash",
|
|
16
18
|
description: "Hash of configuration used to generate this resource (for change detection)",
|
|
17
19
|
title: "Config Hash",
|
|
18
|
-
sidebar: false
|
|
20
|
+
sidebar: false,
|
|
21
|
+
editor: false
|
|
19
22
|
end
|
|
20
23
|
end
|
|
21
24
|
end
|
|
@@ -6,16 +6,20 @@ module Archsight::Annotations::Git
|
|
|
6
6
|
base.class_eval do
|
|
7
7
|
annotation "git/updatedAt",
|
|
8
8
|
description: "Date when the resource was last updated",
|
|
9
|
-
title: "Updated At"
|
|
9
|
+
title: "Updated At",
|
|
10
|
+
editor: false
|
|
10
11
|
annotation "git/updatedBy",
|
|
11
12
|
description: "Email of person who last updated the resource",
|
|
12
|
-
title: "Updated By"
|
|
13
|
+
title: "Updated By",
|
|
14
|
+
editor: false
|
|
13
15
|
annotation "git/reviewedAt",
|
|
14
16
|
description: "Date when the resource was last reviewed",
|
|
15
|
-
title: "Reviewed At"
|
|
17
|
+
title: "Reviewed At",
|
|
18
|
+
editor: false
|
|
16
19
|
annotation "git/reviewedBy",
|
|
17
20
|
description: "Email of person who last reviewed the resource",
|
|
18
|
-
title: "Reviewed By"
|
|
21
|
+
title: "Reviewed By",
|
|
22
|
+
editor: false
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Interface module adds interface-specific annotations to resource classes
|
|
4
|
+
module Archsight::Annotations::Interface
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.class_eval do
|
|
7
|
+
annotation "architecture/encoding",
|
|
8
|
+
description: "Data encoding format",
|
|
9
|
+
filter: :list,
|
|
10
|
+
title: "Encoding"
|
|
11
|
+
annotation "architecture/title",
|
|
12
|
+
description: "Interface title",
|
|
13
|
+
title: "Title"
|
|
14
|
+
annotation "architecture/openapi",
|
|
15
|
+
description: "OpenAPI specification version",
|
|
16
|
+
filter: :word,
|
|
17
|
+
title: "OpenAPI"
|
|
18
|
+
annotation "architecture/version",
|
|
19
|
+
description: "API or interface version",
|
|
20
|
+
filter: :word,
|
|
21
|
+
title: "Version",
|
|
22
|
+
sidebar: false
|
|
23
|
+
annotation "architecture/status",
|
|
24
|
+
description: "Lifecycle status",
|
|
25
|
+
filter: :word,
|
|
26
|
+
enum: %w[General-Availability Early-Access Development],
|
|
27
|
+
title: "Status"
|
|
28
|
+
annotation "architecture/visibility",
|
|
29
|
+
description: "API visibility (public, private, internal)",
|
|
30
|
+
filter: :word,
|
|
31
|
+
enum: %w[public private internal],
|
|
32
|
+
title: "Visibility"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/archsight/cli.rb
CHANGED
|
@@ -19,6 +19,7 @@ module Archsight
|
|
|
19
19
|
option :production, type: :boolean, default: false, desc: "Run in production mode"
|
|
20
20
|
option :disable_reload, type: :boolean, default: false, desc: "Disable the reload button in the UI"
|
|
21
21
|
option :enable_logging, type: :boolean, default: nil, desc: "Enable request logging (default: false in dev, true in prod)"
|
|
22
|
+
option :inline_edit, type: :boolean, default: false, desc: "Enable inline editing (save directly to source files)"
|
|
22
23
|
def web
|
|
23
24
|
configure_resources
|
|
24
25
|
require "archsight/web/application"
|
|
@@ -26,6 +27,7 @@ module Archsight
|
|
|
26
27
|
env = options[:production] ? :production : :development
|
|
27
28
|
Archsight::Web::Application.configure_environment!(env, logging: options[:enable_logging])
|
|
28
29
|
Archsight::Web::Application.set :reload_enabled, !options[:disable_reload]
|
|
30
|
+
Archsight::Web::Application.set :inline_edit_enabled, options[:inline_edit]
|
|
29
31
|
Archsight::Web::Application.setup_mcp!
|
|
30
32
|
Archsight::Web::Application.run!(port: options[:port], bind: options[:host])
|
|
31
33
|
rescue Archsight::ResourceError => e
|
|
@@ -102,7 +104,7 @@ module Archsight
|
|
|
102
104
|
|
|
103
105
|
# Create database that loads from resources directory
|
|
104
106
|
# Only load Import resources to avoid validation errors on incomplete resources
|
|
105
|
-
db = Archsight::Database.new(resources_dir, verbose: options[:verbose], only_kinds: [
|
|
107
|
+
db = Archsight::Database.new(resources_dir, verbose: options[:verbose], only_kinds: %w[Import BusinessActor], verify: false)
|
|
106
108
|
|
|
107
109
|
if options[:dry_run]
|
|
108
110
|
puts "Execution Plan:"
|
|
@@ -191,7 +193,7 @@ module Archsight
|
|
|
191
193
|
def filter_analyses(db)
|
|
192
194
|
analyses = db.instances_by_kind("Analysis").values
|
|
193
195
|
analyses = analyses.select { |a| Regexp.new(options[:filter], Regexp::IGNORECASE).match?(a.name) } if options[:filter]
|
|
194
|
-
analyses
|
|
196
|
+
analyses
|
|
195
197
|
end
|
|
196
198
|
|
|
197
199
|
def print_analysis_dry_run(analyses)
|