Skip to content

Commit 325566b

Browse files
castlerCopilot
andcommitted
[rules score] add AoU forwarding to dependable elements
Implement automatic and chain-forwarding of Assumptions of Use (AoU) between dependable elements: - Add ForwardedAoUInfo provider carrying own and chain-forwarded AoU lobster entries as depsets - Add aou_lobster field to AssumptionsOfUseInfo for lobster extraction from AoU TRLC sources - Extend dependable_element rule to collect own AoUs from deps, receive chain-forwarded AoUs, and emit ForwardedAoUInfo - Add aou_forwarding attribute accepting a YAML file that selects which received AoUs to forward further (with mandatory justification) - Add aou_forwarding_to_lobster.py tool for filtering received AoUs based on the forwarding YAML (supports versioned lobster tags) - Add lobster_aou.yaml config for lobster-trlc extraction of AoU records - Extend lobster_de.conf.tpl with Forwarded AoUs tier Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bd09ae2 commit 325566b

9 files changed

Lines changed: 360 additions & 2 deletions

File tree

bazel/rules/rules_score/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ py_binary(
7676
visibility = ["//visibility:public"],
7777
)
7878

79+
# AoU forwarding filter: filters received AoU lobster entries for chain-forwarding
80+
py_binary(
81+
name = "aou_forwarding_to_lobster",
82+
srcs = ["src/aou_forwarding_to_lobster.py"],
83+
imports = ["src"],
84+
main = "src/aou_forwarding_to_lobster.py",
85+
visibility = ["//visibility:public"],
86+
deps = [
87+
requirement("pyyaml"),
88+
],
89+
)
90+
7991
# HTML merge tool
8092
py_binary(
8193
name = "sphinx_html_merge",

bazel/rules/rules_score/lobster/config/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ filegroup(
4444
visibility = ["//visibility:public"],
4545
)
4646

47+
filegroup(
48+
name = "aou_config",
49+
srcs = ["lobster_aou.yaml"],
50+
visibility = ["//visibility:public"],
51+
)
52+
4753
# ---------------------------------------------------------------------------
4854
# Lobster report config templates: static structure with {PLACEHOLDER} markers
4955
# for source file lists. Used by rules_score to generate per-target configs
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
# lobster-trlc configuration for Assumptions of Use records.
14+
inputs:
15+
- .
16+
conversion-rules:
17+
- package: ScoreReq
18+
record-type: AoU
19+
namespace: req
20+
version-field: version
21+
description-fields: description

bazel/rules/rules_score/lobster/config/lobster_de.conf.tpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ requirements "Feature Requirements" {
22
{FEAT_REQ_SOURCES}
33
}
44

5+
requirements "Forwarded AoUs" {
6+
{FORWARDED_AOU_SOURCES}
7+
}
8+
59
requirements "Component Requirements" {
610
{COMP_REQ_SOURCES}{COMP_REQ_TRACE}}
711

bazel/rules/rules_score/private/assumptions_of_use.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ following S-CORE process guidelines. Assumptions of Use define the safety-releva
1919
operating conditions and constraints for a Safety Element out of Context (SEooC).
2020
"""
2121

22+
load("@lobster//:lobster.bzl", "subrule_lobster_trlc")
2223
load("@trlc//:trlc.bzl", "TrlcProviderInfo", "trlc_requirements_test")
2324
load("//bazel/rules/rules_score:providers.bzl", "AssumptionsOfUseInfo", "ComponentRequirementsInfo", "FeatureRequirementsInfo", "SphinxSourcesInfo")
2425
load("//bazel/rules/rules_score/private:rst_to_trlc.bzl", "rst_srcs_to_trlc")
@@ -61,6 +62,14 @@ def _assumptions_of_use_impl(ctx):
6162

6263
all_srcs = depset(rendered_files)
6364

65+
# Generate lobster file from AoU TRLC sources for traceability forwarding
66+
all_trlc_files = []
67+
for src in ctx.attr.srcs:
68+
all_trlc_files.extend(src[DefaultInfo].files.to_list())
69+
aou_lobster_file = None
70+
if all_trlc_files and ctx.file.lobster_config:
71+
aou_lobster_file, _ = subrule_lobster_trlc(all_trlc_files, ctx.file.lobster_config)
72+
6473
# Collect requirements providers and lobster files
6574
reqs = []
6675
lobster_files = []
@@ -84,6 +93,7 @@ def _assumptions_of_use_impl(ctx):
8493
DefaultInfo(files = all_srcs),
8594
AssumptionsOfUseInfo(
8695
srcs = depset(transitive = lobster_files),
96+
aou_lobster = depset([aou_lobster_file] if aou_lobster_file else []),
8797
name = ctx.label.name,
8898
),
8999
SphinxSourcesInfo(
@@ -111,13 +121,19 @@ _assumptions_of_use = rule(
111121
mandatory = False,
112122
doc = "List of feature or component requirements targets that these Assumptions of Use trace to",
113123
),
124+
"lobster_config": attr.label(
125+
allow_single_file = True,
126+
mandatory = True,
127+
doc = "Lobster YAML configuration file for AoU traceability extraction.",
128+
),
114129
"_renderer": attr.label(
115130
default = Label("@trlc//tools/trlc_rst:trlc_rst"),
116131
executable = True,
117132
allow_files = True,
118133
cfg = "exec",
119134
),
120135
},
136+
subrules = [subrule_lobster_trlc],
121137
)
122138

123139
# ============================================================================
@@ -129,6 +145,7 @@ def assumptions_of_use(
129145
srcs,
130146
requirements = [],
131147
ref_package = None,
148+
lobster_config = Label("//bazel/rules/rules_score/lobster/config:aou_config"),
132149
**kwargs):
133150
"""Define Assumptions of Use following S-CORE process guidelines.
134151
@@ -149,6 +166,8 @@ def assumptions_of_use(
149166
traceability as defined in the S-CORE process.
150167
ref_package: Optional TRLC package prefix used for ``derived_from``
151168
cross-references when converting RST sources.
169+
lobster_config: Lobster YAML configuration for AoU traceability
170+
extraction. Defaults to the standard S-CORE AoU config.
152171
visibility: Bazel visibility specification for the generated targets.
153172
154173
Generated Targets:
@@ -179,6 +198,7 @@ def assumptions_of_use(
179198
name = name,
180199
srcs = trlc_srcs,
181200
requirements = requirements,
201+
lobster_config = lobster_config,
182202
**kwargs
183203
)
184204
trlc_requirements_test(

bazel/rules/rules_score/private/dependable_element.bzl

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ load(
2929
"//bazel/rules/rules_score:providers.bzl",
3030
"ArchitecturalDesignInfo",
3131
"AssumedSystemRequirementsInfo",
32+
"AssumptionsOfUseInfo",
3233
"CertifiedScope",
3334
"ComponentInfo",
3435
"DependabilityAnalysisInfo",
3536
"DependableElementInfo",
3637
"DependableElementLobsterInfo",
3738
"FeatureRequirementsInfo",
39+
"ForwardedAoUInfo",
3840
"SphinxIndexFileInfo",
3941
"SphinxModuleInfo",
4042
"SphinxNeedsInfo",
@@ -1011,19 +1013,72 @@ def _dependable_element_index_impl(ctx):
10111013
cm_list = [sa_lobster_files["controlmeasures.lobster"]] if "controlmeasures.lobster" in sa_lobster_files else []
10121014
rc_list = [sa_lobster_files["root_causes.lobster"]] if "root_causes.lobster" in sa_lobster_files else []
10131015

1016+
# =========================================================================
1017+
# AoU Forwarding: collect own AoUs and received AoUs from deps
1018+
# =========================================================================
1019+
1020+
# Collect own AoU lobster files from assumptions_of_use targets
1021+
own_aou_lobster_files = []
1022+
for aou_target in ctx.attr.assumptions_of_use:
1023+
if AssumptionsOfUseInfo in aou_target:
1024+
own_aou_lobster_files.append(aou_target[AssumptionsOfUseInfo].aou_lobster)
1025+
1026+
own_aou_lobster_depset = depset(transitive = own_aou_lobster_files)
1027+
1028+
# Collect forwarded AoU lobster files from deps (received AoUs)
1029+
received_aou_lobster_files = []
1030+
for dep in ctx.attr.processed_deps:
1031+
if ForwardedAoUInfo in dep:
1032+
fwd_info = dep[ForwardedAoUInfo]
1033+
received_aou_lobster_files.append(fwd_info.own_aou_lobster)
1034+
received_aou_lobster_files.append(fwd_info.chain_forwarded_lobster)
1035+
1036+
received_aou_lobster_depset = depset(transitive = received_aou_lobster_files)
1037+
received_aou_list = received_aou_lobster_depset.to_list()
1038+
1039+
# Chain-forwarding: if aou_forwarding YAML is provided, filter received AoUs
1040+
chain_forwarded_lobster_depset = depset()
1041+
if ctx.file.aou_forwarding and received_aou_list:
1042+
chain_forwarded_lobster_file = ctx.actions.declare_file(
1043+
ctx.label.name + "/chain_forwarded_aous.lobster",
1044+
)
1045+
fwd_args = ctx.actions.args()
1046+
fwd_args.add("--yaml", ctx.file.aou_forwarding)
1047+
fwd_args.add("--output", chain_forwarded_lobster_file)
1048+
fwd_args.add("--input-lobster")
1049+
fwd_args.add_all(received_aou_list)
1050+
ctx.actions.run(
1051+
inputs = [ctx.file.aou_forwarding] + received_aou_list,
1052+
outputs = [chain_forwarded_lobster_file],
1053+
executable = ctx.executable._aou_forwarding_tool,
1054+
arguments = [fwd_args],
1055+
progress_message = "Filtering chain-forwarded AoUs for %s" % ctx.label.name,
1056+
mnemonic = "AoUForwarding",
1057+
)
1058+
chain_forwarded_lobster_depset = depset([chain_forwarded_lobster_file])
1059+
output_files.append(chain_forwarded_lobster_file)
1060+
10141061
lobster_report_file = None
10151062
lobster_html_report = None
10161063
lobster_rst_dir = None
10171064
lobster_files = []
10181065
if feat_req_list:
1066+
# Build comp_req trace-to lines (Feature Requirements + optionally Forwarded AoUs)
1067+
comp_req_trace_lines = ""
1068+
if comp_req_list:
1069+
comp_req_trace_lines = " trace to: \"Feature Requirements\";\n"
1070+
if received_aou_list:
1071+
comp_req_trace_lines += " trace to: \"Forwarded AoUs\";\n"
1072+
10191073
lobster_config = ctx.actions.declare_file(ctx.label.name + "/de_traceability_config")
10201074
ctx.actions.expand_template(
10211075
template = ctx.file._lobster_de_template,
10221076
output = lobster_config,
10231077
substitutions = {
10241078
"{FEAT_REQ_SOURCES}": format_lobster_sources(feat_req_list),
1079+
"{FORWARDED_AOU_SOURCES}": format_lobster_sources(received_aou_list),
10251080
"{COMP_REQ_SOURCES}": format_lobster_sources(comp_req_list),
1026-
"{COMP_REQ_TRACE}": (" trace to: \"Feature Requirements\";\n") if comp_req_list else "",
1081+
"{COMP_REQ_TRACE}": comp_req_trace_lines,
10271082
"{ARCH_SOURCES}": format_lobster_sources(comp_arch_list),
10281083
"{UNIT_TEST_SOURCES}": format_lobster_sources(comp_test_list),
10291084
"{PUBLIC_API_SOURCES}": format_lobster_sources(interface_req_list),
@@ -1033,7 +1088,7 @@ def _dependable_element_index_impl(ctx):
10331088
},
10341089
)
10351090

1036-
all_lobster_inputs = feat_req_list + comp_req_list + comp_arch_list + comp_test_list + interface_req_list + fm_list + cm_list + rc_list
1091+
all_lobster_inputs = feat_req_list + comp_req_list + comp_arch_list + comp_test_list + interface_req_list + fm_list + cm_list + rc_list + received_aou_list
10371092
lobster_report_file = subrule_lobster_report(all_lobster_inputs, lobster_config)
10381093
lobster_html_report = subrule_lobster_html_report(lobster_report_file)
10391094

@@ -1077,6 +1132,10 @@ def _dependable_element_index_impl(ctx):
10771132
lobster_html_report = lobster_html_report,
10781133
lobster_rst_dir = lobster_rst_dir,
10791134
),
1135+
ForwardedAoUInfo(
1136+
own_aou_lobster = own_aou_lobster_depset,
1137+
chain_forwarded_lobster = chain_forwarded_lobster_depset,
1138+
),
10801139
OutputGroupInfo(debug = depset([validation_log])),
10811140
]
10821141

@@ -1132,6 +1191,11 @@ _dependable_element_index = rule(
11321191
default = [],
11331192
doc = "Dependencies on other dependable element modules (submodules).",
11341193
),
1194+
"aou_forwarding": attr.label(
1195+
allow_single_file = [".yaml", ".yml"],
1196+
default = None,
1197+
doc = "Optional YAML file listing received AoU IDs to further-forward to this element's own dependees. Only needed for chain-forwarding.",
1198+
),
11351199
"integrity_level": attr.string(
11361200
mandatory = True,
11371201
values = _INTEGRITY_LEVELS,
@@ -1159,6 +1223,12 @@ _dependable_element_index = rule(
11591223
cfg = "exec",
11601224
doc = "Lobster RST report tool for generating the multi-page Sphinx traceability report.",
11611225
),
1226+
"_aou_forwarding_tool": attr.label(
1227+
default = Label("//bazel/rules/rules_score:aou_forwarding_to_lobster"),
1228+
executable = True,
1229+
cfg = "exec",
1230+
doc = "Tool for filtering received AoU lobster entries based on chain-forwarding YAML.",
1231+
),
11621232
},
11631233
**VERBOSITY_ATTR
11641234
),
@@ -1272,6 +1342,7 @@ def dependable_element(
12721342
integrity_level,
12731343
checklists = [],
12741344
deps = [],
1345+
aou_forwarding = None,
12751346
maturity = "release",
12761347
sphinx = Label("//bazel/rules/rules_score:score_build"),
12771348
testonly = True,
@@ -1308,6 +1379,9 @@ def dependable_element(
13081379
safety checklists and verification documents.
13091380
deps: Optional list of other module targets this element depends on.
13101381
Cross-references will work automatically.
1382+
aou_forwarding: Optional label to a YAML file listing received AoU IDs
1383+
to further-forward to this element's own dependees. Only needed for
1384+
chain-forwarding received AoUs that this element cannot handle.
13111385
sphinx: Label to sphinx build binary. Default: //bazel/rules/rules_score:score_build
13121386
testonly: If True, only testonly targets can depend on this target.
13131387
@@ -1337,6 +1411,7 @@ def dependable_element(
13371411
tests = tests,
13381412
deps = deps,
13391413
processed_deps = processed_deps,
1414+
aou_forwarding = aou_forwarding,
13401415
integrity_level = integrity_level,
13411416
maturity = maturity,
13421417
testonly = testonly,

bazel/rules/rules_score/providers.bzl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,25 @@ AssumptionsOfUseInfo = provider(
122122
doc = "Provider for assumptions of use artifacts.",
123123
fields = {
124124
"srcs": "Depset of .lobster traceability files collected from all linked requirements targets.",
125+
"aou_lobster": "Depset of .lobster traceability files generated from the AoU TRLC sources themselves (used for forwarding to dependees).",
125126
"requirements": "List of FeatureRequirementsInfo or ComponentRequirementsInfo providers this AoU traces to.",
126127
"name": "Name of the assumptions of use target.",
127128
},
128129
)
129130

131+
ForwardedAoUInfo = provider(
132+
doc = """Carries AoU lobster files that dependees must satisfy.
133+
134+
When a dependable element is listed in another element's `deps`, the
135+
dependee receives this element's AoUs and must either link them in its
136+
lobster traceability report or further-forward them.
137+
""",
138+
fields = {
139+
"own_aou_lobster": "Depset of .lobster files from this element's own assumptions_of_use (always forwarded to dependees).",
140+
"chain_forwarded_lobster": "Depset of .lobster files for received AoUs being further-forwarded (selected via aou_forwarding YAML).",
141+
},
142+
)
143+
130144
ComponentInfo = provider(
131145
doc = "Provider for component artifacts.",
132146
fields = {

bazel/rules/rules_score/requirements.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
myst-parser
2+
pyyaml
23
readthedocs-sphinx-ext
34
rst2pdf
45
sphinx

0 commit comments

Comments
 (0)