Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,11 @@ use_repo(pip, "pip_cr_checker")
# rules_multitool merges all hub() calls sharing the same hub_name across the
# module graph. score_tooling doesn't declare its own lockfile for that
# default hub to avoid overriding those (pinned, multi-platform) entries with
# a narrower one, and doesn't `use_repo` it either: third_party/format and
# a narrower one. The default "multitool" repo is imported via use_repo() to
# satisfy the module extension validation; third_party/format and
# third_party/lint consume those tools indirectly via
# @aspect_rules_lint//lint:ruff_bin, //lint:ty_bin, //format:ruff,
# //format:yamlfmt -- none of which require score_tooling itself to see the
# "multitool" repo name.
# //format:yamlfmt.
multitool = use_extension("@rules_multitool//multitool:extension.bzl", "multitool")

# Actionlint Hub -- actionlint has no equivalent in aspect_rules_lint's bundled
Expand All @@ -303,7 +303,7 @@ multitool.hub(
hub_name = "actionlint_hub",
lockfile = "tools/actionlint.lock.json",
)
use_repo(multitool, "actionlint_hub")
use_repo(multitool, "actionlint_hub", "multitool")

register_toolchains("@actionlint_hub//toolchains:all")

Expand Down
4 changes: 3 additions & 1 deletion bazel/rules/rules_score/examples/seooc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ component(
name = "component_example",
components = [
"//unit_1:unit_1",
"//unit_2:unit_2",
":sub_component_example",
],
# component_requirements_sub is also listed here (in addition to
Expand All @@ -55,6 +54,9 @@ component(
# not just units (see docs/user_guide/architectural_design.rst).
component(
name = "sub_component_example",
components = [
"//unit_2:unit_2",
],
requirements = [
"//docs/requirements:component_requirements_sub",
"//docs/requirements:feature_requirements",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
package "Safety Software SEooC Example" as safety_software_seooc_example <<SEooC>> {
component "ComponentExample" as component_example <<component>> {
component "Unit 1" as unit_1 <<unit>>
component "Unit 2" as unit_2 <<unit>>
component "Sub Component Example" as sub_component_example <<component>>
component "Sub Component Example" as sub_component_example <<component>> {
component "Unit 2" as unit_2 <<unit>>
}

interface "InternalInterface" as InternalInterface
unit_1 -l-( InternalInterface
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/examples/seooc/docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ load(
"assumptions_of_use",
"glossary",
)
load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("@score_tooling//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")

assumptions_of_use(
name = "sample_aous",
Expand All @@ -26,7 +26,7 @@ assumptions_of_use(
visibility = ["//visibility:public"],
)

trlc_requirements_test(
trlc_check_test(
name = "aous_test",
reqs = [
":sample_aous",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ the assumptions a Safety Element out of Context (SEooC) makes about the system
it will be integrated into. Feature requirements are derived from them.
"""

load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")
load("//bazel/rules/rules_score/private:requirements.bzl", "score_requirements_rule")

# ============================================================================
Expand Down Expand Up @@ -89,7 +89,7 @@ def assumed_system_requirements(
image_srcs = image_srcs,
**kwargs
)
trlc_requirements_test(
trlc_check_test(
name = name + "_test",
reqs = [":" + name],
**kwargs
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/private/assumptions_of_use.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Traceability to feature/assumed-system requirements is established at the
dependable_element level (via its own `requirements` attribute), not here.
"""

load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")
load("//bazel/rules/rules_score/private:requirements.bzl", "score_requirements_rule")

# ============================================================================
Expand Down Expand Up @@ -94,7 +94,7 @@ def assumptions_of_use(
ref_package = ref_package or "",
**kwargs
)
trlc_requirements_test(
trlc_check_test(
name = name + "_test",
reqs = [":" + name],
**kwargs
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/private/component_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Component requirements are derived from feature requirements and define the
specific requirements for a software component.
"""

load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")
load("//bazel/rules/rules_score/private:requirements.bzl", "score_requirements_rule")

# ============================================================================
Expand Down Expand Up @@ -83,7 +83,7 @@ def component_requirements(
image_srcs = image_srcs,
**kwargs
)
trlc_requirements_test(
trlc_check_test(
name = name + "_test",
reqs = [":" + name],
**kwargs
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/private/feature_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ must implement. They are derived from Assumed System Requirements and feed into
Component Requirements.
"""

load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")
load("//bazel/rules/rules_score/private:requirements.bzl", "score_requirements_rule")

# ============================================================================
Expand Down Expand Up @@ -89,7 +89,7 @@ def feature_requirements(
image_srcs = image_srcs,
**kwargs
)
trlc_requirements_test(
trlc_check_test(
name = name + "_test",
reqs = [":" + name],
**kwargs
Expand Down
3 changes: 2 additions & 1 deletion bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ load(
load("@score_tooling//bazel/rules/rules_score:sphinx_toolchain.bzl", "score_sphinx_toolchain")
load("@score_tooling//cpp/libclang:libclang_toolchain.bzl", "libclang_toolchain")
load("@trlc//:trlc.bzl", "trlc_requirements", "trlc_requirements_test")
load("@score_tooling//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")
load(
":html_generation_test.bzl",
"auto_config_generation_test",
Expand Down Expand Up @@ -1355,7 +1356,7 @@ trlc_requirements(
spec = ["@score_tooling//bazel/rules/rules_score/trlc/config:score_requirements_model"],
)

trlc_requirements_test(
trlc_check_test(
name = "safety_measures_types_test",
reqs = [":safety_measures_fixtures"],
)
Expand Down
6 changes: 5 additions & 1 deletion bazel/rules/rules_score/trlc/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# *******************************************************************************

load("@trlc//:trlc.bzl", "trlc_requirements", "trlc_requirements_test", "trlc_specification")
load("//bazel/rules/rules_score/trlc/config/test:trlc_check_test.bzl", "trlc_check_test")

trlc_specification(
name = "score_requirements_model",
Expand All @@ -21,7 +22,10 @@ trlc_specification(
visibility = ["//visibility:public"],
)

trlc_requirements_test(
# The model contains ASIL checks that crash TRLC 3.0.0's VCG (CVC5 backend)
# when --verify is used. Use trlc_check_test (no --verify) so the model parses
# and checks evaluate at runtime without triggering the VCG crash.
trlc_check_test(
name = "score_requirements_model_test",
reqs = [
":score_requirements_model",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,20 @@ tuple AssumedSystemReqId {
version Integer
}

// FeatReqSourceId uses the abstract RequirementSafety item type (instead of the
// concrete AssumedSystemReq) so that TRLC can resolve the inherited `safety`
// field in checks FeatReq. At runtime every item is still an AssumedSystemReq
// instance; the broader declared type is only needed to satisfy TRLC 3.0.0's
// field-access resolution rules.
tuple FeatReqSourceId {
item RequirementSafety
separator @
version Integer
}

type FeatReq "High-level feature requirement derived from one or more AssumedSystemReq items." extends RequirementSafety {
derived_from "One or more versioned references to the AssumedSystemReq items this feature requirement is derived from."
AssumedSystemReqId[1 .. *]
FeatReqSourceId[1 .. *]
}

tuple FeatReqId {
Expand Down Expand Up @@ -182,3 +193,33 @@ tuple Measure {

// abstract type StdReq extends Requirement {
// }

///////////////////////////////
// Safety Checks
///////////////////////////////

// Note: use trlc_check_test (no --verify) for these checks; TRLC 3.0.0's VCG crashes on forall over union/abstract tuple item fields.
// ASIL ordering: QM < B < D. If Asil gains new levels, revisit every branch below.

// FeatReq: ASIL must not decrease from the upstream AssumedSystemReq.
// FeatReqSourceId.item is RequirementSafety (abstract) so TRLC resolves the
// inherited `safety` field correctly in this check block.
checks FeatReq {
(forall upstream in derived_from =>
not ((upstream.item.safety == Asil.B and safety == Asil.QM) or
(upstream.item.safety == Asil.D and safety != Asil.D))),
error "ASIL level of derived requirement must be at least the same as the upstream requirement",
safety
}

// CompReq: ASIL must not decrease from any upstream FeatReq or AssumedSystemReq.
// CompReqSourceId.item is a union [FeatReq, AssumedSystemReq]; TRLC resolves
// the `safety` field via the common ancestor RequirementSafety.
checks CompReq {
derived_from == null or
(forall upstream in derived_from =>
not ((upstream.item.safety == Asil.B and safety == Asil.QM) or
(upstream.item.safety == Asil.D and safety != Asil.D))),
error "ASIL level of derived requirement must be at least the same as the upstream requirement",
safety
}
123 changes: 123 additions & 0 deletions bazel/rules/rules_score/trlc/config/test/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@trlc//:trlc.bzl", "trlc_requirements")
load(":trlc_check_test.bzl", "trlc_check_test")

# ==============================================================================
# ASIL Safety Check — Test Fixtures
#
# Scenario matrix:
#
# Upstream ASIL | Downstream ASIL | Result
# ---------------+-------------------+--------
# QM | QM | PASS (same level)
# B | B | PASS (same level)
# B | D | PASS (raised level)
# D | D | PASS (same level)
# B | QM | FAIL (degraded — check fires)
# D | B | FAIL (degraded — check fires)
# D | QM | FAIL (degraded — check fires)
#
# ==============================================================================

# ------------------------------------------------------------------------------
# Shared upstream requirements (ASRs at QM / B / D)
# ------------------------------------------------------------------------------

trlc_requirements(
name = "valid_asr",
srcs = ["valid_asr.trlc"],
spec = ["//bazel/rules/rules_score/trlc/config:score_requirements_model"],
visibility = ["//visibility:private"],
)

# ------------------------------------------------------------------------------
# Valid scenarios — ASIL level is maintained or raised downstream
# bazel test //bazel/rules/rules_score/trlc/config/test:asil_check_valid_test
# Expected result: PASS
# ------------------------------------------------------------------------------

trlc_requirements(
name = "valid_feat_req",
srcs = ["valid_feat_req.trlc"],
spec = ["//bazel/rules/rules_score/trlc/config:score_requirements_model"],
deps = [":valid_asr"],
visibility = ["//visibility:private"],
)

trlc_requirements(
name = "valid_comp_req",
srcs = ["valid_comp_req.trlc"],
spec = ["//bazel/rules/rules_score/trlc/config:score_requirements_model"],
deps = [
":valid_asr",
":valid_feat_req",
],
visibility = ["//visibility:private"],
)

# Only the leaf target is passed — its depset transitively includes valid_feat_req
# and valid_asr (via deps), so the RSL spec file is passed to TRLC exactly once.
trlc_check_test(
name = "asil_check_valid_test",
reqs = [":valid_comp_req"],
)

# ------------------------------------------------------------------------------
# Invalid scenarios — ASIL level is degraded downstream (check violations)
#
# These targets are tagged "manual" because trlc_requirements_test will FAIL
# as expected when TRLC reports the ASIL check violation as an error.
# Run them manually to observe the error output:
#
# bazel test //bazel/rules/rules_score/trlc/config/test:asil_check_invalid_feat_test
# bazel test //bazel/rules/rules_score/trlc/config/test:asil_check_invalid_comp_test
# ------------------------------------------------------------------------------

trlc_requirements(
name = "invalid_feat_req",
srcs = ["invalid_feat_req.trlc"],
spec = ["//bazel/rules/rules_score/trlc/config:score_requirements_model"],
deps = [":valid_asr"],
tags = ["manual"],
visibility = ["//visibility:private"],
)

# Expected result: FAIL — 3 ASIL check violations (FEAT_INVALID_001/002/003)
# invalid_feat_req deps on valid_asr, so all needed files are included transitively.
trlc_check_test(
name = "asil_check_invalid_feat_test",
reqs = [":invalid_feat_req"],
tags = ["manual"],
)

trlc_requirements(
name = "invalid_comp_req",
srcs = ["invalid_comp_req.trlc"],
spec = ["//bazel/rules/rules_score/trlc/config:score_requirements_model"],
deps = [
":valid_asr",
":valid_feat_req",
],
tags = ["manual"],
visibility = ["//visibility:private"],
)

# Expected result: FAIL — 4 ASIL check violations (COMP_INVALID_001/002/003/004)
# invalid_comp_req deps on valid_asr and valid_feat_req, so all needed files are included transitively.
trlc_check_test(
name = "asil_check_invalid_comp_test",
reqs = [":invalid_comp_req"],
tags = ["manual"],
)
Loading