Initial commit. monorepo deps are copied in a dirty way to the vendor folder

This commit is contained in:
Florian Frank committed 2026-09-18 16:58:29 +02:00
commit 06593ac488
53 files changed
+7692

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+93
View File
@@ -0,0 +1,93 @@
Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
+422
View File
@@ -0,0 +1,422 @@
/* The print stylesheet of the SAST/SCA report.
*
* Follows the design sample in `sample_report_template/`. Everything is expressed here rather than
* in the template: the template places content, this decides what it looks like, and the two are
* changed for different reasons.
*
* Space Grotesk throughout, with a monospace face for anything a reader might have to type or
* compare character by character -- identifiers, paths, package URLs, CVSS vectors, VEX
* justifications. That distinction is the one typographic rule the whole report rests on.
*/
@font-face {
font-family: "Space Grotesk";
font-weight: 400;
src: url("fonts/SpaceGrotesk-Regular.ttf");
}
@font-face {
font-family: "Space Grotesk";
font-weight: 500;
src: url("fonts/SpaceGrotesk-Medium.ttf");
}
@font-face {
font-family: "Space Grotesk";
font-weight: 700;
src: url("fonts/SpaceGrotesk-Bold.ttf");
}
/* Shipped rather than asked of the host. `monospace` resolves to whatever a machine happens to
have -- DejaVu on one, Andale on another -- and a report whose identifiers change shape between
two machines is a report nobody can compare. Space Mono is the companion face to Space Grotesk. */
@font-face {
font-family: "Space Mono";
font-weight: 400;
src: url("fonts/SpaceMono-Regular.ttf");
}
@font-face {
font-family: "Space Mono";
font-weight: 700;
src: url("fonts/SpaceMono-Bold.ttf");
}
:root {
--ink: #1a1a1a;
--muted: #55585c;
--rule: #1a1a1a;
--border: #c9cbcd;
--header-fill: #e7e8ea;
--label-fill: #f4f5f6;
/* The filtering reason is the one row that argues rather than states, and it is tinted so that
it reads as an aside even when the page is skimmed. */
--aside-fill: #fdf5ea;
--critical: #d0021b;
--high: #e8710a;
--medium: #f0ad20;
--low: #1f9d55;
}
@page {
size: A4;
margin: 22mm 18mm 18mm 18mm;
@bottom-left {
content: string(scan-footer);
font-family: "Space Grotesk", sans-serif;
font-size: 6.5pt;
color: var(--muted);
}
@bottom-center {
content: counter(page);
font-family: "Space Grotesk", sans-serif;
font-size: 6.5pt;
color: var(--muted);
}
@bottom-right {
content: string(date-footer);
font-family: "Space Grotesk", sans-serif;
font-size: 6.5pt;
color: var(--muted);
}
}
html {
font-family: "Space Grotesk", sans-serif;
font-size: 8.5pt;
line-height: 1.45;
color: var(--ink);
}
body {
margin: 0;
}
code,
.mono {
font-family: "Space Mono", monospace;
font-size: 0.93em;
}
/* Carried into the running footer on every page. Set once, on the cover. */
.footer-scan {
string-set: scan-footer content();
}
.footer-date {
string-set: date-footer content();
}
.footer-scan,
.footer-date {
position: absolute;
visibility: hidden;
}
/* --- Cover ------------------------------------------------------------------------------- */
.cover-mark {
text-align: right;
margin-bottom: 42mm;
}
.cover-mark img {
height: 15mm;
}
.cover-title {
font-size: 19pt;
font-weight: 400;
margin: 0 0 9mm 0;
}
/* --- Headings ---------------------------------------------------------------------------- */
/* A section heading and the rule under it are one thing, so the rule belongs to the heading and
cannot be separated from it by a page break. */
h1 {
font-size: 12.5pt;
font-weight: 700;
margin: 12mm 0 4mm 0;
padding-bottom: 1.6mm;
border-bottom: 0.8pt solid var(--rule);
break-after: avoid;
}
h1:first-of-type {
margin-top: 0;
}
h2 {
font-size: 9pt;
font-weight: 700;
margin: 7mm 0 2.5mm 0;
break-after: avoid;
}
h3 {
font-size: 8.5pt;
font-weight: 700;
margin: 5mm 0 2mm 0;
break-after: avoid;
}
p {
margin: 0 0 2.5mm 0;
}
p.note {
color: var(--ink);
max-width: 155mm;
}
/* --- Definition rows --------------------------------------------------------------------- */
/* Label left, value right, on one grid so that every block of them lines up down the page even
when they are separated by headings. */
.facts {
width: 100%;
border-collapse: collapse;
margin-bottom: 3mm;
}
.facts td {
padding: 0.7mm 0;
vertical-align: top;
}
.facts td:first-child {
width: 46mm;
padding-right: 4mm;
}
.facts.wide td:first-child {
width: 62mm;
}
.facts tr.gap td {
padding-top: 4mm;
}
/* --- Ledger tables (severity counts, languages) ------------------------------------------- */
/* Ruled above and below with hairlines between, and a heavier line before the total: the shape a
reader already knows from an invoice, used for the same reason -- the last row is a sum. */
.ledger {
width: 62%;
border-collapse: collapse;
margin-bottom: 4mm;
}
.ledger th,
.ledger td {
padding: 1.4mm 1mm;
border-bottom: 0.4pt solid var(--border);
}
.ledger thead th {
border-bottom: 0.8pt solid var(--rule);
text-align: left;
font-weight: 700;
}
.ledger td:last-child {
text-align: right;
}
.ledger tr.total td {
border-top: 0.8pt solid var(--rule);
border-bottom: none;
font-weight: 700;
}
/* --- Grid tables -------------------------------------------------------------------------- */
.grid {
width: 100%;
border-collapse: collapse;
margin-bottom: 4mm;
/* A table that splits across a page keeps its header on the second half. */
break-inside: auto;
}
.grid th,
.grid td {
border: 0.4pt solid var(--border);
padding: 1.6mm 2mm;
vertical-align: top;
text-align: left;
}
.grid thead th {
background: var(--header-fill);
font-weight: 700;
}
.grid tr.total td {
font-weight: 700;
}
.grid tr,
.facts tr {
break-inside: avoid;
}
/* --- Cards -------------------------------------------------------------------------------- */
/* One finding, as a titled block of label/value rows. Kept on one page where it fits: a card split
down the middle loses the thing that makes it a card. */
.card {
width: 100%;
border-collapse: collapse;
margin-bottom: 3.5mm;
break-inside: avoid;
}
.card caption {
background: var(--header-fill);
border: 0.4pt solid var(--border);
padding: 1.6mm 2mm;
text-align: left;
font-weight: 700;
caption-side: top;
}
.card th,
.card td {
border: 0.4pt solid var(--border);
padding: 1.6mm 2mm;
vertical-align: top;
text-align: left;
}
.card th {
width: 34mm;
background: var(--label-fill);
font-weight: 400;
}
.card tr.aside th,
.card tr.aside td {
background: var(--aside-fill);
}
/* The justification itself, set as the token it is rather than as prose about a token. */
.token {
font-family: "Space Mono", monospace;
font-size: 0.93em;
background: #ffffff;
border: 0.4pt solid var(--border);
border-radius: 1mm;
padding: 0.3mm 1.2mm;
}
/* --- Severity ----------------------------------------------------------------------------- */
.sev {
font-weight: 700;
}
.sev-critical {
color: var(--critical);
}
.sev-high {
color: var(--high);
}
.sev-medium {
color: var(--medium);
}
.sev-low {
color: var(--low);
}
/* --- Distribution bars --------------------------------------------------------------------- */
/* Label, count, then one bar made of stacked severity segments. The bar is scaled against the
largest row rather than against the total, so the shape of the distribution is what is read and
the busiest row fills the width. */
.bars {
width: 100%;
border-collapse: collapse;
margin-bottom: 1.5mm;
}
.bars td {
border: 0.4pt solid var(--border);
padding: 1.2mm 2mm;
vertical-align: middle;
}
.bars td.count {
width: 12mm;
text-align: right;
}
.bars td.track {
width: 50%;
padding: 1.2mm 2mm;
}
.bar {
height: 3mm;
width: 100%;
/* The segments are inline-block, so the newlines between them in the template would be
rendered as spaces and push a full-width bar onto a second line. */
font-size: 0;
white-space: nowrap;
}
.bar span {
display: inline-block;
height: 3mm;
vertical-align: top;
}
.seg-critical {
background: var(--critical);
}
.seg-high {
background: var(--high);
}
.seg-medium {
background: var(--medium);
}
.seg-low {
background: var(--low);
}
/* A distribution and its legend travel together. Where the pair does not fit, it moves to the
next page whole rather than leaving a stranded row and an orphaned key behind. */
.block {
break-inside: avoid;
}
.legend {
font-size: 7.5pt;
color: var(--ink);
margin-bottom: 5mm;
}
.legend .key {
display: inline-block;
width: 2.4mm;
height: 2.4mm;
margin-right: 1.2mm;
}
.legend .item {
margin-right: 4mm;
}
.legend .caveat {
color: var(--muted);
}
+182
View File
@@ -0,0 +1,182 @@
{#
The SAST/SCA report, after the design sample in `sample_report_template/`.
This file places content and nothing else: every dimension, colour and rule lives in `report.css`.
Each section is guarded by the data it needs, so a report of a scan that ran half the pipeline is
the same document with fewer sections rather than a document full of empty tables.
The context this expects is described by `layout.CONTEXT`, and `sample.sample_context()` builds a
complete one.
#}
{# A value is drawn by what it is, not by where it sits: an identifier, a path or a CVSS vector is
set in the monospace face wherever it appears, and a severity carries its colour. #}
{% macro value(row) %}
{% if row.token %}<span class="token">{{ row.token }}</span> — {% endif %}
{% if row.kind == "severity" %}
<span class="sev sev-{{ row.value|lower }}">{{ row.value }}</span>
{% elif row.kind == "mono" %}
<span class="mono">{{ row.value }}</span>
{% else %}
{{ row.value }}
{% endif %}
{% endmacro %}
{% macro facts(rows, wide=false) %}
<table class="facts{% if wide %} wide{% endif %}">
{% for row in rows %}
<tr{% if row.gap %} class="gap"{% endif %}>
<td>{{ row.label }}:</td>
<td>{{ value(row) }}</td>
</tr>
{% endfor %}
</table>
{% endmacro %}
{% macro card(title, rows) %}
{# Wrapped, because break-inside on the table does not hold its caption: the title would stay on
one page while the rows it titles moved to the next. #}
<div class="block">
<table class="card">
<caption>{{ title }}</caption>
{% for row in rows %}
<tr{% if row.aside %} class="aside"{% endif %}>
<th>{{ row.label }}</th>
<td>{{ value(row) }}</td>
</tr>
{% endfor %}
</table>
</div>
{% endmacro %}
{# Scaled against the busiest row, not against the total: what is read off a row of these is which
one is the outlier, and a scale set by the sum flattens all of them. #}
{% macro distribution(rows, legend) %}
{# The bars and the legend that decodes them are one thing; a break between them leaves a reader
with coloured segments and no key. #}
<div class="block">
<table class="bars">
{% for row in rows %}
<tr>
<td{% if row.mono %} class="mono"{% endif %}>{{ row.label }}</td>
<td class="count">{{ row.count }}</td>
<td class="track">
<div class="bar">
{% for part in row.parts %}
<span class="seg-{{ part.severity|lower }}" style="width: {{ part.share }}%"></span>
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
</table>
<div class="legend">
{% for item in legend.entries %}
<span class="item"><span class="key seg-{{ item.severity|lower }}"></span>{{ item.label }}</span>
{% endfor %}
{% if legend.caveat %}<span class="caveat">— {{ legend.caveat }}</span>{% endif %}
</div>
</div>
{% endmacro %}
{% macro grid(table) %}
<table class="grid">
<thead>
<tr>{% for column in table.columns %}<th>{{ column }}</th>{% endfor %}</tr>
</thead>
<tbody>
{% for row in table.rows %}
<tr{% if row.total %} class="total"{% endif %}>
{% for cell in row.cells %}
<td>{% if cell is mapping %}{{ value(cell) }}{% else %}{{ cell }}{% endif %}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}
{# ------------------------------------------------------------------------------------------ #}
<span class="footer-scan">Scan: {{ cover.scan_id }}</span>
<span class="footer-date">{{ cover.footer_date }}</span>
<div class="cover-mark">
<img src="{{ cover.logo }}" alt="CipherCell" />
</div>
<div class="cover-title">{{ cover.title }}</div>
{{ facts(cover.identity) }}
{% if cover.severity_ledger %}
<h2>{{ cover.severity_ledger.title }}</h2>
<table class="ledger">
{% for row in cover.severity_ledger.rows %}
<tr{% if row.total %} class="total"{% endif %}>
<td>{{ row.label }}</td>
<td>{{ row.count }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if scan %}
<h1 style="break-before: page">{{ scan.title }}</h1>
{{ facts(scan.overview, wide=true) }}
{% for stage in scan.stages %}
<h3>{{ stage.title }}</h3>
{{ facts(stage.rows, wide=true) }}
{% if stage.table %}{{ grid(stage.table) }}{% endif %}
{% endfor %}
{% endif %}
{% if project %}
<h1 style="break-before: page">{{ project.title }}</h1>
{{ facts(project.overview, wide=true) }}
{% if project.languages %}
<h2>{{ project.languages.title }}</h2>
<table class="ledger">
{% for row in project.languages.rows %}
<tr{% if row.total %} class="total"{% endif %}>
<td>{{ row.label }}</td>
<td>{{ row.share }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
{% if summary %}
<h1>{{ summary.title }}</h1>
{{ facts(summary.overview, wide=true) }}
{% for block in summary.distributions %}
<h2>{{ block.title }}</h2>
{{ distribution(block.rows, block.legend) }}
{% endfor %}
{% endif %}
{% if critical %}
<h2 style="break-before: page">{{ critical.title }}</h2>
{{ grid(critical.table) }}
{% endif %}
{% for section in sections %}
<h1{% if section.new_page %} style="break-before: page"{% endif %}>{{ section.title }}</h1>
{% for group in section.groups %}
<h2>{{ group.title }}</h2>
{% if group.note %}<p class="note">{{ group.note }}</p>{% endif %}
{% for entry in group.cards %}
{{ card(entry.title, entry.rows) }}
{% endfor %}
{% if group.table %}
{% if group.table.title %}<h2>{{ group.table.title }}</h2>{% endif %}
{{ grid(group.table) }}
{% endif %}
{% endfor %}
{% endfor %}