Skip to content
Merged
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
7 changes: 4 additions & 3 deletions bazel/rules/rules_score/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ Also generates a `_test` target that validates metamodel compliance.
```starlark
assumptions_of_use(
name = "my_aou",
requirements = [":my_feat_reqs"],
srcs = ["assumptions.rst"],
)
```

**`bazel build`** — collects LOBSTER traceability files from the linked
requirements and exposes them via `AssumptionsOfUseInfo`.
**`bazel build`** — renders the AoU TRLC/RST sources and exposes their
LOBSTER traceability file via `AssumptionsOfUseInfo.aou_lobster`. Tracing to
feature/assumed-system requirements is established at the `dependable_element`
level (via its own `requirements` attribute), not here.

---

Expand Down
163 changes: 28 additions & 135 deletions bazel/rules/rules_score/private/assumptions_of_use.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,127 +14,22 @@
"""
Assumptions of Use build rules for S-CORE projects.

This module provides macros and rules for defining Assumptions of Use (AoU)
following S-CORE process guidelines. Assumptions of Use define the safety-relevant
This module provides a macro for defining Assumptions of Use (AoU) following
S-CORE process guidelines. Assumptions of Use define the safety-relevant
operating conditions and constraints for a Safety Element out of Context (SEooC).
"""

load("@lobster//:lobster.bzl", "subrule_lobster_trlc")
load("@trlc//:trlc.bzl", "TrlcProviderInfo", "trlc_requirements_test")
load("//bazel/rules/rules_score:providers.bzl", "AssumptionsOfUseInfo", "ComponentRequirementsInfo", "FeatureRequirementsInfo", "SphinxSourcesInfo")
load("//bazel/rules/rules_score/private:rst_to_trlc.bzl", "rst_srcs_to_trlc")

# ============================================================================
# Private Rule Implementation
# ============================================================================

def _assumptions_of_use_impl(ctx):
"""Implementation for assumptions_of_use rule.

Collects assumptions of use source files and links them to their
parent feature requirements through providers.
Implemented as the "aou" kind of the shared score_requirements_rule (see
requirements.bzl), so raw .trlc files, .rst files, and existing
TrlcProviderInfo-emitting targets (e.g. trlc_requirements) may all be passed
as srcs, matching the conventions of feature_requirements,
component_requirements, and assumed_system_requirements.

Args:
ctx: Rule context

Returns:
List of providers including DefaultInfo and AssumptionsOfUseInfo
"""

# Render each TRLC source to RST for Sphinx
rendered_files = []
for src in ctx.attr.srcs:
trlc_provider = src[TrlcProviderInfo]
rendered_file = ctx.actions.declare_file("{}_{}.rst".format(ctx.attr.name, src.label.name))
args = ctx.actions.args()
args.add("--output", rendered_file.path)
args.add("--input-dir", ".")
args.add("--title", ctx.label.name.replace("_", " ").title())
args.add("--source-files")
args.add_all(trlc_provider.reqs)
ctx.actions.run(
inputs = src[DefaultInfo].files,
outputs = [rendered_file],
arguments = [args],
executable = ctx.executable._renderer,
)
rendered_files.append(rendered_file)

all_srcs = depset(rendered_files)

# Generate lobster file from AoU TRLC sources for traceability forwarding
all_trlc_files = []
for src in ctx.attr.srcs:
all_trlc_files.extend(src[DefaultInfo].files.to_list())
aou_lobster_file = None
if all_trlc_files and ctx.file.lobster_config:
aou_lobster_file, _ = subrule_lobster_trlc(all_trlc_files, ctx.file.lobster_config)

# Collect requirements providers and lobster files
reqs = []
lobster_files = []
for req in ctx.attr.requirements:
if FeatureRequirementsInfo in req:
info = req[FeatureRequirementsInfo]
reqs.append(info)
lobster_files.append(info.srcs)
elif ComponentRequirementsInfo in req:
info = req[ComponentRequirementsInfo]
reqs.append(info)
lobster_files.append(info.srcs)

# Collect transitive sphinx sources from requirements
transitive = [all_srcs]
for req in ctx.attr.requirements:
if SphinxSourcesInfo in req:
transitive.append(req[SphinxSourcesInfo].deps)

return [
DefaultInfo(files = all_srcs),
AssumptionsOfUseInfo(
srcs = depset(transitive = lobster_files),
aou_lobster = depset([aou_lobster_file] if aou_lobster_file else []),
name = ctx.label.name,
),
SphinxSourcesInfo(
srcs = all_srcs,
deps = depset(transitive = transitive),
aux_srcs = depset(),
),
]

# ============================================================================
# Rule Definition
# ============================================================================
Traceability to feature/assumed-system requirements is established at the
dependable_element level (via its own `requirements` attribute), not here.
"""

_assumptions_of_use = rule(
implementation = _assumptions_of_use_impl,
doc = "Collects Assumptions of Use documents with traceability to feature requirements",
attrs = {
"srcs": attr.label_list(
providers = [TrlcProviderInfo],
mandatory = True,
doc = "trlc_requirements targets containing Assumptions of Use specifications",
),
"requirements": attr.label_list(
providers = [[FeatureRequirementsInfo], [ComponentRequirementsInfo]],
mandatory = False,
doc = "List of feature or component requirements targets that these Assumptions of Use trace to",
),
"lobster_config": attr.label(
allow_single_file = True,
mandatory = True,
doc = "Lobster YAML configuration file for AoU traceability extraction.",
),
"_renderer": attr.label(
default = Label("@trlc//tools/trlc_rst:trlc_rst"),
executable = True,
allow_files = True,
cfg = "exec",
),
},
subrules = [subrule_lobster_trlc],
)
load("@trlc//:trlc.bzl", "trlc_requirements_test")
load("//bazel/rules/rules_score/private:requirements.bzl", "score_requirements_rule")

# ============================================================================
# Public Macro
Expand All @@ -143,7 +38,7 @@ _assumptions_of_use = rule(
def assumptions_of_use(
name,
srcs,
requirements = [],
deps = [],
ref_package = None,
lobster_config = Label("//bazel/rules/rules_score/lobster/config:aou_config"),
**kwargs):
Expand All @@ -157,13 +52,13 @@ def assumptions_of_use(
Args:
name: The name of the assumptions of use target. Used as the base
name for all generated targets.
srcs: List of labels to trlc_requirements targets containing the
Assumptions of Use specifications as defined in the S-CORE
process. RST files containing ``aou_req`` directives are also
accepted and will be converted to TRLC automatically.
requirements: Optional list of labels to feature or component requirements
targets that these Assumptions of Use trace to. Establishes
traceability as defined in the S-CORE process.
srcs: List of TRLC/RST/label sources defining the Assumptions of Use.
Accepts raw ``.trlc`` files, ``.rst`` files containing ``aou_req``
directives (converted to TRLC automatically), and/or labels to
existing targets that already provide TrlcProviderInfo (e.g.
``trlc_requirements`` targets).
deps: Optional list of other requirement targets (providing
TrlcProviderInfo) needed for cross-reference parsing.
ref_package: Optional TRLC package prefix used for ``derived_from``
cross-references when converting RST sources.
lobster_config: Lobster YAML configuration for AoU traceability
Expand All @@ -174,12 +69,11 @@ def assumptions_of_use(
<name>: Main assumptions of use target providing AssumptionsOfUseInfo
<name>_test: TRLC validation test for the assumptions of use sources

Example using trlc_requirements targets:
Example using raw TRLC sources directly:
```starlark
assumptions_of_use(
name = "my_assumptions_of_use",
srcs = [":my_aous_trlc"],
requirements = [":my_feature_requirements"],
srcs = ["assumptions_of_use.trlc"],
)
```

Expand All @@ -188,21 +82,20 @@ def assumptions_of_use(
assumptions_of_use(
name = "my_assumptions_of_use",
srcs = ["docs/assumptions_of_use.rst"],
requirements = [":my_feature_requirements"],
)
```
"""
trlc_srcs = rst_srcs_to_trlc(name, srcs, ref_package = ref_package or "")

_assumptions_of_use(
score_requirements_rule(
name = name,
srcs = trlc_srcs,
requirements = requirements,
srcs = srcs,
deps = deps,
req_kind = "aou",
lobster_config = lobster_config,
ref_package = ref_package or "",
**kwargs
)
trlc_requirements_test(
name = name + "_test",
reqs = trlc_srcs,
reqs = [":" + name],
**kwargs
)
6 changes: 6 additions & 0 deletions bazel/rules/rules_score/private/dependable_element.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,11 @@ def _dependable_element_index_impl(ctx):

own_aou_lobster_depset = depset(transitive = own_aou_lobster_files)

own_assumptions_of_use_info = AssumptionsOfUseInfo(
aou_lobster = own_aou_lobster_depset,
name = ctx.label.name,
)

# Collect forwarded AoU lobster files from deps (received AoUs)
received_aou_lobster_files = []
for dep in ctx.attr.processed_deps:
Expand Down Expand Up @@ -1209,6 +1214,7 @@ def _dependable_element_index_impl(ctx):
own_aou_lobster = own_aou_lobster_depset,
chain_forwarded_lobster = chain_forwarded_lobster_depset,
),
own_assumptions_of_use_info,
OutputGroupInfo(debug = depset(validation_output_files)),
]

Expand Down
38 changes: 31 additions & 7 deletions bazel/rules/rules_score/private/requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public-facing macros.

load("@lobster//:lobster.bzl", "subrule_lobster_trlc")
load("@trlc//:trlc.bzl", "TrlcProviderInfo", "subrule_trlc_image_stage")
load("//bazel/rules/rules_score:providers.bzl", "AssumedSystemRequirementsInfo", "ComponentRequirementsInfo", "FeatureRequirementsInfo", "SphinxSourcesInfo")
load("//bazel/rules/rules_score:providers.bzl", "AssumedSystemRequirementsInfo", "AssumptionsOfUseInfo", "ComponentRequirementsInfo", "FeatureRequirementsInfo", "SphinxSourcesInfo")
load("//bazel/rules/rules_score/private:rst_to_trlc.bzl", "rst_to_trlc")

# ============================================================================
Expand Down Expand Up @@ -99,6 +99,11 @@ def _requirements_impl(ctx):
srcs = depset([lobster_file]),
name = ctx.label.name,
)
elif ctx.attr.req_kind == "aou":
req_provider = AssumptionsOfUseInfo(
aou_lobster = depset([lobster_file]),
name = ctx.label.name,
)
else: # assumed_system
req_provider = AssumedSystemRequirementsInfo(
srcs = depset([lobster_file]),
Expand Down Expand Up @@ -153,7 +158,7 @@ _score_requirements_rule = rule(
doc = "Other requirement targets whose TRLC records are needed for cross-reference parsing.",
),
"req_kind": attr.string(
values = ["feature", "component", "assumed_system"],
values = ["feature", "component", "assumed_system", "aou"],
mandatory = True,
doc = "Kind of requirements; determines which domain provider is emitted.",
),
Expand Down Expand Up @@ -192,16 +197,28 @@ def score_requirements_rule(
**kwargs):
"""Macro wrapper around _score_requirements_rule with RST support.

Any .rst files in srcs are converted to .trlc via rst_to_trlc before
being passed to the underlying rule. .trlc sources are passed through
unchanged.
Each entry in srcs is classified as follows:
- ".rst" files are converted to .trlc via rst_to_trlc and treated as
own sources.
- ".trlc" files are passed through unchanged as own sources.
- Any other label is assumed to already provide TrlcProviderInfo (e.g.
an existing trlc_requirements/assumed_system_requirements/... target)
and is routed to ``deps`` instead, since only raw TRLC files may be
listed in the underlying rule's ``srcs``.

Args:
ref_package: TRLC package prefix used for derived_from cross-references
when converting RST sources (e.g. "AssumedSystemRequirements" for
feature requirements that derive from ASR).

Returns:
List of resolved labels corresponding to srcs (after any .rst-to-.trlc
conversion), in the same order. Useful for callers that need to run
trlc_requirements_test against the same source set.
"""
trlc_srcs = []
extra_deps = []
resolved_srcs = []
for i, src in enumerate(srcs):
if type(src) == type("") and src.endswith(".rst"):
gen_name = "_{}_rst_gen_{}".format(name, i)
Expand All @@ -211,15 +228,22 @@ def score_requirements_rule(
ref_package = ref_package,
)
trlc_srcs.append(":" + gen_name)
else:
resolved_srcs.append(":" + gen_name)
elif type(src) == type("") and src.endswith(".trlc"):
trlc_srcs.append(src)
resolved_srcs.append(src)
else:
extra_deps.append(src)
resolved_srcs.append(src)

_score_requirements_rule(
name = name,
srcs = trlc_srcs,
deps = deps,
deps = deps + extra_deps,
req_kind = req_kind,
lobster_config = lobster_config,
spec = spec,
**kwargs
)

return resolved_srcs
4 changes: 1 addition & 3 deletions bazel/rules/rules_score/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,8 @@ AnalysisInfo = provider(
AssumptionsOfUseInfo = provider(
doc = "Provider for assumptions of use artifacts.",
fields = {
"srcs": "Depset of .lobster traceability files collected from all linked requirements targets.",
"aou_lobster": "Depset of .lobster traceability files generated from the AoU TRLC sources themselves (used for forwarding to dependees).",
"requirements": "List of FeatureRequirementsInfo or ComponentRequirementsInfo providers this AoU traces to.",
"name": "Name of the assumptions of use target.",
"name": "Name of the assumptions of use (or dependable_element) target.",
},
)

Expand Down
2 changes: 0 additions & 2 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ component_requirements(
assumptions_of_use(
name = "aous",
srcs = ["fixtures/seooc_test/assumptions_of_use.rst"],
requirements = [":feat_req"],
)

# - Architecture Design: wp__component_arch
Expand Down Expand Up @@ -719,7 +718,6 @@ component_requirements(
assumptions_of_use(
name = "aous_rst",
srcs = ["fixtures/rst_requirements/assumptions_of_use.rst"],
requirements = [":feat_req_rst"],
)

asr_rst_output_test(
Expand Down
4 changes: 2 additions & 2 deletions bazel/rules/rules_score/test/requirements_rst_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ def _aous_rst_provider_test_impl(ctx):
)
asserts.true(
env,
info.srcs != None,
"AssumptionsOfUseInfo should have a srcs field",
info.aou_lobster != None,
"AssumptionsOfUseInfo should have an aou_lobster field",
)

return analysistest.end(env)
Expand Down
Loading