Skip to content

Commit c54b299

Browse files
committed
v3.8.1
1 parent 1aff140 commit c54b299

File tree

16 files changed

+1304
-522
lines changed

16 files changed

+1304
-522
lines changed

Dockerfile.cache

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
# syntax=docker/dockerfile:1
22

33
ARG CACHE_PATH=/tmp/rl-secure.cache
4-
5-
FROM rockylinux:9-minimal
4+
FROM rockylinux/rockylinux:9-minimal
65
ARG CACHE_PATH
6+
77
COPY scripts/* /opt/rl-scanner/
88
RUN --mount=type=secret,id=rlsecure_license --mount=type=secret,id=rlsecure_sitekey <<EORUN
99
set -e
1010
echo ${CACHE_PATH}
11+
1112
microdnf upgrade -y
1213
microdnf install -y --nodocs python3-pip
1314
pip3 install --no-cache-dir rl-deploy
1415
pip3 uninstall setuptools -y
1516
microdnf remove pip -y
1617
microdnf clean all
18+
1719
rl-deploy cache \
1820
--no-tracking \
1921
--location=${CACHE_PATH} \
2022
--encoded-key=$(cat /run/secrets/rlsecure_license) \
2123
--site-key=$(cat /run/secrets/rlsecure_sitekey)
2224

23-
chmod 755 /opt/rl-scanner/entrypoint /opt/rl-scanner/rl-scan /opt/rl-scanner/rl-prune
25+
chmod 755 /opt/rl-scanner/entrypoint
26+
chmod 755 /opt/rl-scanner/rl-prune
27+
chmod 755 /opt/rl-scanner/rl-scan
28+
chmod 755 /opt/rl-scanner/rl-scan-url
29+
chmod 755 /opt/rl-scanner/rl-scan-purl
2430
EORUN
31+
2532
ENV PATH="/opt/rl-scanner:${PATH}"
2633
ENTRYPOINT [ "/opt/rl-scanner/entrypoint" ]

Dockerfile.no_cache

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
# syntax=docker/dockerfile:1
22

3-
FROM rockylinux:9-minimal
3+
FROM rockylinux/rockylinux:9-minimal
4+
45
COPY scripts/* /opt/rl-scanner/
56
RUN <<EORUN
67
set -e
8+
79
microdnf upgrade -y
810
microdnf install -y --nodocs python3-pip
911
pip3 install --no-cache-dir rl-deploy
1012
pip3 uninstall setuptools -y
1113
microdnf remove pip -y
1214
microdnf clean all
1315

14-
chmod 755 /opt/rl-scanner/entrypoint /opt/rl-scanner/rl-scan /opt/rl-scanner/rl-prune
16+
chmod 755 /opt/rl-scanner/entrypoint
17+
chmod 755 /opt/rl-scanner/rl-prune
18+
chmod 755 /opt/rl-scanner/rl-scan
19+
chmod 755 /opt/rl-scanner/rl-scan-url
20+
chmod 755 /opt/rl-scanner/rl-scan-purl
21+
1522
EORUN
23+
1624
ENV PATH="/opt/rl-scanner:${PATH}"
1725
ENTRYPOINT [ "/opt/rl-scanner/entrypoint" ]

Makefile

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ LINE_LENGTH = 120
1616
PL_LINTERS = "eradicate,mccabe,pycodestyle,pyflakes,pylint"
1717
PL_IGNORE = C0114,C0115,C0116
1818
SCRIPTS = scripts/
19+
RL_SCAN = scripts/rl-scan
20+
RL_PRUNE = scripts/rl-prune
21+
RL_INTRYPOINT = scripts/entrypoint
1922

2023

2124
.PHONY: build-without-cache build-with-cache push clean format pycheck test test.%
@@ -57,14 +60,34 @@ pylama:
5760
--max-line-length $(LINE_LENGTH) \
5861
--linters $(PL_LINTERS) \
5962
--ignore $(PL_IGNORE) \
60-
$(SCRIPTS)
63+
$(SCRIPTS)/*
6164

62-
mypy:
65+
mypy: mypy_a mypy_prune mypy_scan mypy_entry
66+
67+
mypy_a:
6368
mypy \
6469
--strict \
6570
--no-incremental \
6671
$(SCRIPTS)
6772

73+
mypy_prune:
74+
mypy \
75+
--strict \
76+
--no-incremental \
77+
$(SCRIPTS) $(RL_PRUNE)
78+
79+
mypy_scan:
80+
mypy \
81+
--strict \
82+
--no-incremental \
83+
$(SCRIPTS) $(RL_SCAN)
84+
85+
mypy_entry:
86+
mypy \
87+
--strict \
88+
--no-incremental \
89+
$(SCRIPTS) $(RL_ENTRYPOINT)
90+
6891

6992
all-tests := $(addprefix test., $(notdir $(wildcard tests/*)))
7093

README.md

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ This optional proxy configuration can be provided using environment variables.
7676
The following environment variables can be used with this image.
7777

7878
| Environment variable | Description |
79-
| :--------- | :------ |
79+
| --------- | ------ |
8080
| `RLSECURE_ENCODED_LICENSE` | Required. The `rl-secure` license file as a Base64-encoded string. Users must encode the contents of your license file, and provide the resulting string with this variable. |
8181
| `RLSECURE_SITE_KEY` | Required. The `rl-secure` license site key. The site key is a string generated by ReversingLabs and sent to users with the license file. |
8282
| `RLSECURE_VAULT_KEY` | Optional. Password vault key to use for preserving and accessing passwords in a package store (rl-store). |
@@ -340,7 +340,7 @@ docker run --rm \
340340
The `rl-scan` helper tool supports the following parameters.
341341

342342
| Parameter | Description |
343-
| :--------- | :------ |
343+
| --------- | ------ |
344344
| `--package-path` | Required. Path to the software package (the file you want to scan). The specified file must exist in the **package source** directory mounted to the container. |
345345
| `--report-path` | Required. Path to the location where you want to store analysis reports. The specified path must exist in the **reports destination** directory mounted to the container. |
346346
| `--report-format` | Required. A comma-separated list of report formats to generate. Supported values: `cyclonedx`, `rl-checks`, `rl-cve`, `rl-html`, `rl-json`, `rl-uri`, `sarif`, `spdx`, `all`. |
@@ -357,7 +357,7 @@ The `rl-scan` helper tool supports the following parameters.
357357
The following `rl-scan` parameters are applicable only when working with a package store.
358358

359359
| Parameter | Description |
360-
| :--------- | :------ |
360+
| --------- | ------ |
361361
| `--rl-store` | Required when using a package store. Path to an existing rl-secure package store that will be used for the scan. Use this parameter when you already have a package store and want to scan the existing package versions inside it or add new package versions to it. The package store directory must be mounted to the container as a part of the Docker command. |
362362
| `--purl` | Required when using a package store. Package URL used for the scan (must be in the format `[pkg:namespace/]<project></package><@version>`). Package URLs are unique identifiers used to associate the scanned package version with a project and a package in the rl-store. This parameter must be used together with `--rl-store`. <br /><br />To use the reproducibility checks feature and analyze a reproducible build artifact of a package version, append `?build=repro` to the package URL of the artifact when scanning it: `--purl=project/[email protected]?build=repro`. |
363363
| `--diff-with` | Optional. Use this parameter to compare (diff) the package version you're scanning against a previous version. The parameter accepts a package version number as the value. The version selected for diffing must exist in the same project and package as the version you're scanning. The package store must be specified with the `--rl-store` parameter. <br /><br /> This parameter is ignored when analyzing reproducible build artifacts. |
@@ -391,7 +391,7 @@ docker run --rm \
391391
The `rl-prune` tool supports the following parameters.
392392

393393
| Parameter | Description |
394-
| :--------- | :------ |
394+
| --------- | ------ |
395395
| `--rl-store` | Required. Path to an existing `rl-secure` store in which you want to prune the data. |
396396
| `--purl` | Required. Package URL to prune, in the format `[pkg:namespace/]<project>[</package>[<@version>]]`. |
397397
| `--before-date` | Optional. Remove all versions scanned before the timestamp specified in ISO-8601 format. |
@@ -400,7 +400,86 @@ The `rl-prune` tool supports the following parameters.
400400
| `--hours-older` | Optional. Remove all versions with the last scan date older than the specified number of hours. |
401401
| `--message-reporter` | Optional. Use it to change the format of output messages (STDOUT) for easier integration with CI tools. Supported values: `text`, `teamcity` |
402402

403-
<!-- 2025-06-18; Spectra Assure CLI 2.8.1 has been released; rl-scanner v3.6.1 -->
403+
## Scanning files from URLs and purls
404+
405+
### rl-scan-url
406+
407+
Scanning a remote HTTP or HTTPS URL can be done with the `rl-scanner` docker image using the `rl-scan-url` command.
408+
409+
example:
410+
411+
```
412+
413+
URL="https://www.7-zip.org/a/7z2500-x64.exe"
414+
415+
docker run --rm \
416+
-u $(id -u):$(id -g) \
417+
-e RLSECURE_ENCODED_LICENSE \
418+
-e RLSECURE_SITE_KEY \
419+
-v $(pwd)/report:/report \
420+
reversinglabs/rl-scanner \
421+
rl-scan-url \
422+
--import-url="${URL}" \
423+
--report-path=/report
424+
```
425+
426+
When the URL requires authentication you can use either `--auth-user`, `--auth-pass` or `--bearer-token` to pass authentication information to the URL request.
427+
428+
### rl-scan-purl
429+
430+
Scanning a PURL present at `secure.software` can be done with the `rl-scanner` docker image using the `rl-scan-purl` command.
431+
For details see the cli documentation at: [importing-files-from-urls](https://docs.secure.software/cli/commands/scan#importing-files-from-urls).
432+
433+
example:
434+
435+
```
436+
437+
PURL="pkg:npm/vue"
438+
439+
docker run --rm \
440+
-u $(id -u):$(id -g) \
441+
-e RLSECURE_ENCODED_LICENSE \
442+
-e RLSECURE_SITE_KEY \
443+
-v $(pwd)/report:/report \
444+
reversinglabs/rl-scanner \
445+
rl-scan-purl \
446+
--import-purl="${PURL}" \
447+
--report-path=/report
448+
```
449+
450+
## Configuration parameters for rl-scan-url and rl-scan-purl
451+
452+
For rl-scan-purl or rl-scan-url commands, instead of the `--package-path` parameter specify the `--import-url` or `--import-purl` parameter.
453+
454+
All other parameters for the `rl-scan` command can be used with `rl-scan-url` or `rl-scan-purl`.
455+
456+
- If the PURL or URL requires **basic authentication**, use the `--auth-user` and `--auth-pass` parameters.
457+
- If the PURL or URL requires **token-based authentication**, use the `--bearer-token` parameter.
458+
459+
### rl-scan-url
460+
461+
Additional parameters for `rl-scan-url`
462+
463+
| Parameter | Description |
464+
| -------------- | ------------ |
465+
| `--import-url` | Mandatory. The URL to the resource you want to scan, only HTTP or HTTPS are supported. |
466+
| `--auth-user` | Optional. If the URL uses `basic authentication` specicy the `user` with this parameter. Cannot be used in combination with `--bearer-token`. |
467+
| `--auth-pass` | Optional. If the URL uses `basic authentication` specicy the `password` with this parameter. Cannot be used in combination with `--bearer-token`. |
468+
| `--bearer-token` | Optional. If the URL uses `token authentication` specicy the `token` with this parameter. Cannot be used in combination with either `--auth--user` or `--auth-pass`. |
469+
470+
### rl-scan-purl
471+
472+
Additional parameters for `rl-scan-purl`
473+
474+
| Parameter | Description |
475+
| -------------- | ------------ |
476+
| `--import-purl` | The purl (package URL) of the software package you want to download and scan, in the format `pkg:<type>`/<item>. Supported package types: `npm`, `gem`, `pypi`, `vsx`, `nuget`. The item specified will be downloaded from Spectra Assure Community (secure.software). |
477+
| `--auth-user` | Optional. If the URL uses `basic authentication` specify the `user` with this parameter. Cannot be used in combination with `--bearer-token`. |
478+
| `--auth-pass` | Optional. If the URL uses `basic authentication` specify the `password` with this parameter. Cannot be used in combination with `--bearer-token`. |
479+
| `--bearer-token` | Optional. If the URL uses `token authentication` specicy the `token` with this parameter. Cannot be used in combination with either `--auth--user` or `--auth-pass`. |
480+
481+
404482
<!-- 2025-07-03; Spectra Assure CLI 2.8.2 has been released; rl-scanner v3.6.2 -->
405483
<!-- 2025-07-17; Spectra Assure CLI 2.9.0 has been released; rl-scanner v3.7.0 -->
406484
<!-- 2025-07-31; Spectra Assure CLI 3.0.0 has been released; rl-scanner v3.8.0 -->
485+
<!-- 2025-08-14; Spectra Assure CLI 3.0.1 has been released; rl-scanner v3.8.1 -->

scripts/cimessages.py

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,26 @@ def create(cls, name: str) -> Any:
1313
return TeamCityMesages()
1414
return TextMessages()
1515

16+
# Public Abstract
17+
@contextmanager
18+
def progress_block(self, msg: str) -> Any:
19+
raise RuntimeError("Abstract: must be defined in subclass")
20+
21+
def info(self, msg: str) -> None:
22+
raise RuntimeError("Abstract: must be defined in subclass")
23+
24+
def scan_result(self, passed: bool, msg: str) -> bool:
25+
raise RuntimeError("Abstract: must be defined in subclass")
26+
1627

1728
class TextMessages(Messages):
18-
def block_start(self, msg: str) -> None:
29+
def _block_start(self, msg: str) -> None:
1930
print(f"Started: {msg}", flush=True)
2031

21-
def block_end(self, msg: str) -> None:
32+
def _block_end(self, msg: str) -> None:
2233
print(f"Finished: {msg}", flush=True)
2334

35+
# Public
2436
def info(self, msg: str) -> None:
2537
print(f"Info: {msg}", flush=True)
2638

@@ -33,49 +45,50 @@ def scan_result(self, passed: bool, msg: str) -> bool:
3345

3446
@contextmanager
3547
def progress_block(self, msg: str) -> Any:
36-
self.block_start(msg)
48+
self._block_start(msg)
3749
yield
38-
self.block_end(msg)
50+
self._block_end(msg)
3951

4052

4153
class TeamCityMesages(Messages):
4254
@classmethod
43-
def service_message(cls, name: str, msg: Any) -> str:
44-
def escape(msg: str) -> str:
55+
def _service_message(cls, name: str, msg: Any) -> str:
56+
def _escape(msg: str) -> str:
4557
escape_map: Dict[str, str] = {"'": "|'", "|": "||", "\n": "|n", "\r": "|r", "[": "|[", "]": "|]"}
4658
return "".join(escape_map.get(x, x) for x in msg)
4759

4860
if isinstance(msg, dict):
49-
msg_content: List[str] = [f"{k}='{escape(v)}'" for k, v in msg.items()]
61+
msg_content: List[str] = [f"{k}='{_escape(v)}'" for k, v in msg.items()]
5062
return f"##teamcity[{name} {' '.join(msg_content)}]"
51-
return f"##teamcity[{name} '{escape(msg)}']"
63+
return f"##teamcity[{name} '{_escape(msg)}']"
5264

53-
def block_start(self, msg: str) -> None:
54-
print(TeamCityMesages.service_message("progressStart", msg), flush=True)
55-
print(TeamCityMesages.service_message("blockOpened", {"name": msg}), flush=True)
65+
def _block_start(self, msg: str) -> None:
66+
print(TeamCityMesages._service_message("progressStart", msg), flush=True)
67+
print(TeamCityMesages._service_message("blockOpened", {"name": msg}), flush=True)
5668

57-
def block_end(self, msg: str) -> None:
58-
print(TeamCityMesages.service_message("blockClosed", {"name": msg}), flush=True)
59-
print(TeamCityMesages.service_message("progressFinish", msg), flush=True)
69+
def _block_end(self, msg: str) -> None:
70+
print(TeamCityMesages._service_message("blockClosed", {"name": msg}), flush=True)
71+
print(TeamCityMesages._service_message("progressFinish", msg), flush=True)
6072

61-
def __build_problem(self, msg: str) -> None:
62-
print(TeamCityMesages.service_message("buildProblem", {"description": msg}), flush=True)
73+
def _build_problem(self, msg: str) -> None:
74+
print(TeamCityMesages._service_message("buildProblem", {"description": msg}), flush=True)
6375

64-
def __build_status(self, msg: str) -> None:
65-
print(TeamCityMesages.service_message("buildStatus", {"text": msg}), flush=True)
76+
def _build_status(self, msg: str) -> None:
77+
print(TeamCityMesages._service_message("buildStatus", {"text": msg}), flush=True)
6678

79+
# Public
6780
def info(self, msg: str) -> None:
68-
print(TeamCityMesages.service_message("message", {"text": msg}), flush=True)
81+
print(TeamCityMesages._service_message("message", {"text": msg}), flush=True)
6982

7083
def scan_result(self, passed: bool, msg: str) -> bool:
7184
if passed:
72-
self.__build_status("Scan result: PASS")
85+
self._build_status("Scan result: PASS")
7386
else:
74-
self.__build_problem(f"Scan result: {msg}... FAIL")
87+
self._build_problem(f"Scan result: {msg}... FAIL")
7588
return False
7689

7790
@contextmanager
7891
def progress_block(self, msg: str) -> Any:
79-
self.block_start(msg)
92+
self._block_start(msg)
8093
yield
81-
self.block_end(msg)
94+
self._block_end(msg)

scripts/constants.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import os
2+
from typing import (
3+
Dict,
4+
List,
5+
Optional,
6+
)
7+
8+
REPORT_FORMATS: Dict[str, str] = { # https://docs.secure.software/api-reference/#tag/Version/operation/getVersionReport
9+
"cyclonedx": "report.cyclonedx.json",
10+
"sarif": "report.sarif.json",
11+
"spdx": "report.spdx.json",
12+
"rl-checks": "report.checks.json",
13+
"rl-cve": "report.cve.csv",
14+
"rl-json": "report.rl.json",
15+
"rl-summary-pdf": "report.summary.pdf",
16+
"rl-uri": "report.uri.csv",
17+
}
18+
19+
# not all report types are supported in pack/rl-safe
20+
RL_SAFE_FORMAT_LIST: List[str] = [
21+
"cyclonedx",
22+
"sarif",
23+
"spdx",
24+
"rl-cve",
25+
"rl-uri",
26+
"all",
27+
]
28+
29+
_DEV: bool = os.getenv("ENVIRONMENT", "") == "DEVELOPMENT"
30+
31+
SCANNER_COMMANDS: List[str] = [
32+
"rl-prune",
33+
"rl-scan",
34+
"rl-scan-url",
35+
"rl-scan-purl",
36+
# "rl-scan-docker",
37+
]
38+
39+
VALID_PURL_TYPES: List[str] = [
40+
"pkg:npm/",
41+
"pkg:pypi/",
42+
"pkg:gem/",
43+
"pkg:nuget/",
44+
"pkg:vsx/",
45+
]
46+
47+
TMP_DIR: str = "/tmp"
48+
49+
CACHE_LOCATION: str = f"{TMP_DIR}/rl-secure.cache"
50+
INSTALL_LOCATION: str = f"{TMP_DIR}/__rlsecure"
51+
RLREPORT_LOCATION: str = f"{TMP_DIR}/__rlsecure-report"
52+
RLSTORE: str = f"{TMP_DIR}/__rlstore"
53+
54+
VAULT_KEY: Optional[str] = None
55+
56+
EXIT_FATAL: int = 101

0 commit comments

Comments
 (0)