cra-kit: address Atwood review (shell safety, validation, samples)

Quote "$@" in gen-sbom --srcs (drop SC2068 disables), pass JSON paths to
python via env var in validate.sh to prevent filename injection, and fail
non-zero instead of warning when SBOM post-processing breaks. Rename the
user_settings.h guard to CRA_KIT_USER_SETTINGS_H, clarify the serialNumber
regex accepts v4 (product) and v5 (component) UUIDs, untrack the gitignored
embedded sample SBOMs, document the SHA-512 CBOM omission, and note sample
timestamp differences in SAMPLE-PROVENANCE.md.

Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
pull/574/head
Sameeh Jubran 2026-06-17 17:27:15 +03:00
parent 04f19f8b2e
commit 8cb188f127
10 changed files with 44 additions and 405 deletions

View File

@ -1,328 +0,0 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:bbd8fa2c-814a-5921-b121-e872fe1b42a2",
"version": 1,
"metadata": {
"timestamp": "2026-05-18T11:56:58Z",
"tools": {
"components": [
{
"type": "application",
"author": "wolfSSL Inc.",
"name": "wolfssl-sbom-gen",
"version": "1.0"
}
]
},
"component": {
"bom-ref": "721ce791-b9c8-5edf-a9d2-ef3b0539043b",
"type": "library",
"supplier": {
"name": "wolfSSL Inc."
},
"name": "wolfssl",
"version": "5.9.1",
"licenses": [
{
"license": {
"id": "GPL-3.0-only"
}
}
],
"copyright": "Copyright (C) 2006-2026 wolfSSL Inc.",
"cpe": "cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*",
"purl": "pkg:github/wolfSSL/wolfssl@v5.9.1",
"hashes": [
{
"alg": "SHA-256",
"content": "3538981aad331ad5cd160abd2b51ce0a5fa1a58b3c51f990e08ca91bb44627a0"
}
],
"externalReferences": [
{
"type": "vcs",
"url": "https://github.com/wolfSSL/wolfssl"
}
],
"properties": [
{
"name": "wolfssl:build:AES_MAX_KEY_SIZE",
"value": "256"
},
{
"name": "wolfssl:build:DH_MAX_SIZE",
"value": "WC_BITS_FULL_BYTES(SP_INT_BITS)"
},
{
"name": "wolfssl:build:ECC_DECODE_EXTRA",
"value": "1"
},
{
"name": "wolfssl:build:ECC_MIN_KEY_SZ",
"value": "224"
},
{
"name": "wolfssl:build:FLASH_QUALIFIER",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_AESGCM",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_AES_CBC",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_AES_DECRYPT",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ALL_CURVES",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_CHECK_KEY",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_DHE",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_KEY_EXPORT",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_KEY_IMPORT",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_SIGN",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_ECC_VERIFY",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_PBKDF1",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_PBKDF2",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_PKCS12",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_PKCS8",
"value": "1"
},
{
"name": "wolfssl:build:HAVE_PUBLIC_FFDHE",
"value": "1"
},
{
"name": "wolfssl:build:LIBWOLFSSL_CMAKE_OUTPUT",
"value": "\"\""
},
{
"name": "wolfssl:build:MIN_FFDHE_BITS",
"value": "0"
},
{
"name": "wolfssl:build:MIN_FFDHE_FP_MAX_BITS",
"value": "(MIN_FFDHE_BITS * 2)"
},
{
"name": "wolfssl:build:NO_OLD_TLS",
"value": "1"
},
{
"name": "wolfssl:build:NO_PSK",
"value": "1"
},
{
"name": "wolfssl:build:NO_RC4",
"value": "1"
},
{
"name": "wolfssl:build:NO_XSTREAM_ALIGN",
"value": "1"
},
{
"name": "wolfssl:build:RSA_DECODE_EXTRA",
"value": "1"
},
{
"name": "wolfssl:build:USE_WOLFSSL_MEMORY",
"value": "1"
},
{
"name": "wolfssl:build:WC_ASYNC_DEV_SIZE",
"value": "0"
},
{
"name": "wolfssl:build:WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_ABI",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_AES_128",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_AES_192",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_AES_256",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_ALERT_COUNT_MAX",
"value": "5"
},
{
"name": "wolfssl:build:WOLFSSL_API",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_ASN_TEMPLATE",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_ASYNC_IO",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_BASE64_DECODE",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_FIPS_VERSION2_CODE",
"value": "WOLFSSL_FIPS_VERSION_CODE"
},
{
"name": "wolfssl:build:WOLFSSL_FIPS_VERSION_CODE",
"value": "WOLFSSL_MAKE_FIPS_VERSION3(0,0,0)"
},
{
"name": "wolfssl:build:WOLFSSL_GENERAL_ALIGNMENT",
"value": "0"
},
{
"name": "wolfssl:build:WOLFSSL_HAVE_PRF",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_LOCAL",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_MAX_EMPTY_RECORDS",
"value": "32"
},
{
"name": "wolfssl:build:WOLFSSL_MIN_AUTH_TAG_SZ",
"value": "12"
},
{
"name": "wolfssl:build:WOLFSSL_PEM_TO_DER",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SMALL_STACK_STATIC",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_ADD_D",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_INVMOD",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_INVMOD_MONT_CT",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_MATH_ALL",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_MUL_D",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_NO_DYN_STACK",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_PRIME_GEN",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_READ_RADIX_10",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_READ_RADIX_16",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_SP_SUB_D",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_TEST_VIS",
"value": "WOLFSSL_API WC_DEPRECATED(\"internal use only\")"
},
{
"name": "wolfssl:build:WOLFSSL_TLS13",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_USER_SETTINGS",
"value": "1"
},
{
"name": "wolfssl:build:WOLFSSL_W64_WRAPPER",
"value": "1"
},
{
"name": "wolfssl:build:XGEN_ALIGN",
"value": "1"
},
{
"name": "wolfssl:sbom:hash-kind",
"value": "source-merkle-omnibor"
},
{
"name": "wolfssl:sbom:source-set",
"value": "aes.c,ecc.c,keys.c,random.c,sha.c,sha256.c,tls.c,tls13.c,wc_port.c"
}
]
}
},
"components": [],
"dependencies": [
{
"ref": "721ce791-b9c8-5edf-a9d2-ef3b0539043b",
"dependsOn": []
}
]
}

View File

@ -1,53 +0,0 @@
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "wolfssl-5.9.1",
"documentNamespace": "urn:uuid:480ff203-f994-5b71-b858-0653e74e422a",
"creationInfo": {
"creators": [
"Organization: wolfSSL Inc.",
"Tool: wolfssl-sbom-gen-1.0"
],
"created": "2026-05-18T11:56:58Z"
},
"packages": [
{
"SPDXID": "SPDXRef-Package-wolfssl",
"name": "wolfssl",
"versionInfo": "5.9.1",
"supplier": "Organization: wolfSSL Inc.",
"downloadLocation": "https://github.com/wolfSSL/wolfssl",
"filesAnalyzed": false,
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "3538981aad331ad5cd160abd2b51ce0a5fa1a58b3c51f990e08ca91bb44627a0"
}
],
"licenseConcluded": "GPL-3.0-only",
"licenseDeclared": "GPL-3.0-only",
"copyrightText": "Copyright (C) 2006-2026 wolfSSL Inc.",
"comment": "Build configuration defines: AES_MAX_KEY_SIZE, DH_MAX_SIZE, ECC_DECODE_EXTRA, ECC_MIN_KEY_SZ, FLASH_QUALIFIER, HAVE_AESGCM, HAVE_AES_CBC, HAVE_AES_DECRYPT, HAVE_ALL_CURVES, HAVE_ECC, HAVE_ECC_CHECK_KEY, HAVE_ECC_DHE, HAVE_ECC_KEY_EXPORT, HAVE_ECC_KEY_IMPORT, HAVE_ECC_SIGN, HAVE_ECC_VERIFY, HAVE_PBKDF1, HAVE_PBKDF2, HAVE_PKCS12, HAVE_PKCS8, HAVE_PUBLIC_FFDHE, LIBWOLFSSL_CMAKE_OUTPUT, MIN_FFDHE_BITS, MIN_FFDHE_FP_MAX_BITS, NO_OLD_TLS, NO_PSK, NO_RC4, NO_XSTREAM_ALIGN, RSA_DECODE_EXTRA, USE_WOLFSSL_MEMORY, WC_ASYNC_DEV_SIZE, WC_TEST_NO_ECC_SIGN_VERIFY_ZERO_DIGEST, WOLFSSL_ABI, WOLFSSL_AES_128, WOLFSSL_AES_192, WOLFSSL_AES_256, WOLFSSL_ALERT_COUNT_MAX, WOLFSSL_API, WOLFSSL_ASN_TEMPLATE, WOLFSSL_ASYNC_IO, WOLFSSL_BASE64_DECODE, WOLFSSL_FIPS_VERSION2_CODE, WOLFSSL_FIPS_VERSION_CODE, WOLFSSL_GENERAL_ALIGNMENT, WOLFSSL_HAVE_PRF, WOLFSSL_LOCAL, WOLFSSL_MAX_EMPTY_RECORDS, WOLFSSL_MIN_AUTH_TAG_SZ, WOLFSSL_PEM_TO_DER, WOLFSSL_SMALL_STACK_STATIC, WOLFSSL_SP_ADD_D, WOLFSSL_SP_INVMOD, WOLFSSL_SP_INVMOD_MONT_CT, WOLFSSL_SP_MATH_ALL, WOLFSSL_SP_MUL_D, WOLFSSL_SP_NO_DYN_STACK, WOLFSSL_SP_PRIME_GEN, WOLFSSL_SP_READ_RADIX_10, WOLFSSL_SP_READ_RADIX_16, WOLFSSL_SP_SUB_D, WOLFSSL_TEST_VIS, WOLFSSL_TLS13, WOLFSSL_USER_SETTINGS, WOLFSSL_W64_WRAPPER, XGEN_ALIGN | hash-kind=source-merkle-omnibor | source-set=aes.c,ecc.c,keys.c,random.c,sha.c,sha256.c,tls.c,tls13.c,wc_port.c",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceType": "cpe23Type",
"referenceLocator": "cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*"
},
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:github/wolfSSL/wolfssl@v5.9.1"
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-Package-wolfssl",
"relationshipType": "DESCRIBES"
}
]
}

View File

@ -19,3 +19,16 @@ Regenerate autotools samples and fix the product stub checksum:
```sh
./scripts/refresh-samples.sh
```
## A note on timestamps
The sample SBOMs carry different `metadata.timestamp` / `created` values because
they were generated at different times, not in a single run:
- `wolfssl-component/` (autotools): `2026-05-12`
- `wolfssl-component-embedded/` (embedded demo): `2026-05-18`
- `product-acme-connect-gateway.*` (product stub): `2026-05-18`
This is expected for hand-pinned samples and does not affect validation
(`scripts/validate.sh` checks cross-document checksums, not timestamps).
Regenerating via `refresh-samples.sh` will update them to the current time.

View File

@ -222,7 +222,8 @@
}
},
"properties": [
{"name": "wolfssl:build:macro", "value": "WOLFSSL_TLS13"}
{"name": "wolfssl:build:macro", "value": "WOLFSSL_TLS13"},
{"name": "wolfssl:note:sha-512-omitted", "value": "SHA-512 is built into the component (crypto-sha-512) but is intentionally absent from this cryptoRefArray: TLS 1.3 handshake/HKDF use SHA-256/SHA-384, not SHA-512. SHA-512 is exposed as a crypto asset for callers, not as a TLS 1.3 protocol dependency."}
]
}
],

View File

@ -2,7 +2,7 @@
# Force embedded gen-sbom (user_settings.h + --srcs) into wolfssl-component-embedded/.
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
export CRA_SBOM_MODE=embedded
export CRA_SBOM_OUT_DIR="$KIT_DIR/auditor-packet/wolfssl-component-embedded"

View File

@ -6,8 +6,9 @@
# CRA_LICENSE_OVERRIDE=<SPDX-id> (optional: e.g. LicenseRef-wolfSSL-Commercial)
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC2015 # `|| true` is a deliberate set -e guard, not if-then-else
WOLFSSL_DIR=${WOLFSSL_DIR:-$(cd "$KIT_DIR/../../wolfssl" 2>/dev/null && pwd || true)}
OUT_DIR=${CRA_SBOM_OUT_DIR:-"$KIT_DIR/auditor-packet/wolfssl-component"}
VERSION_FILE="$KIT_DIR/VERSION"
@ -98,7 +99,6 @@ _run_embedded() {
if _py=$(_python_with_pcpp); then
echo " Using $_py (pcpp) for --user-settings"
# shellcheck disable=SC2068
"$_py" "$GEN" \
--name wolfssl --version "$VERSION" \
--license-file "$WOLFSSL_DIR/LICENSING" \
@ -106,7 +106,7 @@ _run_embedded() {
--user-settings-include "$WOLFSSL_DIR" \
--user-settings-include "$KIT_DIR" \
--user-settings-define WOLFSSL_USER_SETTINGS \
--srcs $@
--srcs "$@"
return 0
fi
@ -134,12 +134,11 @@ _run_embedded() {
PYTHON=python3
command -v python3 >/dev/null 2>&1 || PYTHON=python
# shellcheck disable=SC2068
"$PYTHON" "$GEN" \
--name wolfssl --version "$VERSION" \
--license-file "$WOLFSSL_DIR/LICENSING" \
--options-h "$DEFINES_H" \
--srcs $@
--srcs "$@"
}
_run_autotools() {
@ -200,8 +199,8 @@ esac
# GHSA / Snyk / Trivy match without per-vendor mapping. Embedded outputs from
# the kit's 9-file demo --srcs list also get a wolfssl:sbom:demo property so a
# downstream auditor cannot mistake them for production-complete SBOMs.
CDX_OUT="$CDX_OUT" SPDX_OUT="$SPDX_OUT" CRA_SBOM_MODE_FINAL="$MODE" \
python3 <<'PY' || echo "WARN: post-process skipped (python3 missing or JSON malformed)"
if ! CDX_OUT="$CDX_OUT" SPDX_OUT="$SPDX_OUT" CRA_SBOM_MODE_FINAL="$MODE" \
python3 <<'PY'
import json, os, pathlib
cdx = pathlib.Path(os.environ["CDX_OUT"])
@ -244,5 +243,10 @@ if spdx.exists():
spdx.write_text(json.dumps(d, indent=2) + "\n")
print(f"Post-processed {spdx.name}: PURL canonicalized" + (", demo watermark added" if demo else ""))
PY
then
echo "ERROR: post-process failed (PURL canonicalization/watermarking incomplete)." >&2
echo " The emitted SBOM may carry pkg:generic PURLs or lack demo watermarks; not trusting it." >&2
exit 1
fi
echo "Done."

View File

@ -12,10 +12,10 @@
# ./scripts/generate-wolfssl-sbom.sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
# shellcheck disable=SC1090
# shellcheck disable=SC1090,SC1091
. "$KIT_DIR/VERSION"
COMP_DIR="$KIT_DIR/auditor-packet/wolfssl-component"
GPL_CDX="$COMP_DIR/wolfssl-${WOLFSSL_VERSION}.cdx.json"

View File

@ -3,14 +3,14 @@
# (SPDX externalDocumentRef checksum + CycloneDX bom externalReference hash).
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
export CRA_SBOM_MODE=autotools
export CRA_SBOM_OUT_DIR="$KIT_DIR/auditor-packet/wolfssl-component"
"$SCRIPT_DIR/generate-wolfssl-sbom.sh"
# shellcheck disable=SC1090
# shellcheck disable=SC1090,SC1091
. "$KIT_DIR/VERSION"
COMPONENT_SPDX="$KIT_DIR/auditor-packet/wolfssl-component/wolfssl-${WOLFSSL_VERSION}.spdx.json"
COMPONENT_CDX="$KIT_DIR/auditor-packet/wolfssl-component/wolfssl-${WOLFSSL_VERSION}.cdx.json"

View File

@ -6,7 +6,7 @@
# validation, when those tools are installed locally.
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
KIT_DIR=$(dirname "$SCRIPT_DIR")
AP="$KIT_DIR/auditor-packet"
PRODUCT_CDX="$AP/product-acme-connect-gateway.cdx.json"
@ -17,20 +17,22 @@ ok() { echo "OK: $*"; }
command -v python3 >/dev/null 2>&1 || fail "python3 required"
# shellcheck disable=SC1090
# shellcheck disable=SC1090,SC1091
. "$KIT_DIR/VERSION" 2>/dev/null || WOLFSSL_VERSION=5.9.1
WOLF_CDX="$AP/wolfssl-component/wolfssl-${WOLFSSL_VERSION}.cdx.json"
WOLF_SPDX="$AP/wolfssl-component/wolfssl-${WOLFSSL_VERSION}.spdx.json"
for f in "$PRODUCT_CDX" "$PRODUCT_SPDX" "$WOLF_CDX" "$WOLF_SPDX"; do
[ -f "$f" ] || fail "missing $f"
python3 -c "import json; json.load(open('$f'))" || fail "invalid JSON: $f"
F="$f" python3 -c "import json, os; json.load(open(os.environ['F']))" || fail "invalid JSON: $f"
ok "$(basename "$f") parses"
done
# CycloneDX 1.6 serialNumber must match urn:uuid:<v4-uuid>; auditors with strict
# validators (cyclonedx-cli) reject anything else. Catch this even when the tool
# isn't installed.
# CycloneDX 1.6 serialNumber must be a well-formed urn:uuid; auditors with strict
# validators (cyclonedx-cli) reject anything else. We accept RFC 4122 versions 1-5:
# the product SBOM uses a random v4, while the wolfSSL component SBOMs use a
# deterministic name-based v5 so regenerated samples keep a stable serialNumber.
# Catch malformed values even when the tool isn't installed.
PRODUCT_CDX="$PRODUCT_CDX" WOLF_CDX="$WOLF_CDX" python3 <<'PY'
import json, os, re, sys
UUID = re.compile(r"^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", re.I)
@ -39,10 +41,10 @@ for env in ("PRODUCT_CDX", "WOLF_CDX"):
path = os.environ[env]
sn = json.load(open(path)).get("serialNumber", "")
if not UUID.match(sn):
errors.append(f"{os.path.basename(path)}: serialNumber {sn!r} is not urn:uuid:<v4>")
errors.append(f"{os.path.basename(path)}: serialNumber {sn!r} is not a urn:uuid:<v1-5>")
if errors:
sys.exit("CycloneDX serialNumber violation(s):\n " + "\n ".join(errors))
print("OK: CycloneDX serialNumbers are valid urn:uuid:<v4>")
print("OK: CycloneDX serialNumbers are valid urn:uuid (v1-5)")
PY
PRODUCT_SPDX="$PRODUCT_SPDX" WOLF_SPDX="$WOLF_SPDX" python3 <<'PY'

View File

@ -1,7 +1,7 @@
/* Demo user_settings.h for CRA Kit embedded SBOM generation.
* Production: replace with your project's user_settings.h (or point gen-sbom at it). */
#ifndef CRA_EVIDENCE_USER_SETTINGS_H
#define CRA_EVIDENCE_USER_SETTINGS_H
#ifndef CRA_KIT_USER_SETTINGS_H
#define CRA_KIT_USER_SETTINGS_H
#define WOLFSSL_TLS13
#define HAVE_AESGCM
@ -9,4 +9,4 @@
#define NO_PSK
#define NO_OLD_TLS
#endif /* CRA_EVIDENCE_USER_SETTINGS_H */
#endif /* CRA_KIT_USER_SETTINGS_H */