Skip to content

Commit ddf7013

Browse files
nglevinluispadron
authored andcommitted
Add an "expected_secure_features" attribute for import (xc)framework rules to declare the secure features that these precompiled artifacts were built with.
Cherry-pick: 07eaefb
1 parent 8b89ef9 commit ddf7013

8 files changed

Lines changed: 279 additions & 12 deletions

File tree

apple/internal/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ bzl_library(
6363
":framework_import_support",
6464
":resources",
6565
":rule_attrs",
66+
":secure_features_support",
6667
"//apple:providers",
6768
"//apple:utils",
6869
"//apple/internal/aspects:swift_usage_aspect",
@@ -120,6 +121,7 @@ bzl_library(
120121
":framework_import_support",
121122
":intermediates",
122123
":rule_attrs",
124+
":secure_features_support",
123125
"//apple:providers",
124126
"//apple/internal/aspects:swift_usage_aspect",
125127
"@bazel_skylib//lib:dicts",

apple/internal/apple_framework_import.bzl

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ load(
6565
"//apple/internal:rule_attrs.bzl",
6666
"rule_attrs",
6767
)
68+
load(
69+
"//apple/internal:secure_features_support.bzl",
70+
"secure_features_support",
71+
)
6872
load(
6973
"//apple/internal/aspects:swift_usage_aspect.bzl",
7074
"SwiftUsageInfo",
@@ -163,6 +167,13 @@ def _apple_dynamic_framework_import_impl(ctx):
163167
framework_imports = ctx.files.framework_imports
164168
label = ctx.label
165169

170+
secure_features_support.validate_expected_secure_features(
171+
disabled_features = disabled_features,
172+
expected_secure_features = ctx.attr.expected_secure_features,
173+
features = features,
174+
rule_label = label,
175+
)
176+
166177
# TODO(b/258492867): Add tree artifacts support when Bazel can handle remote actions with
167178
# symlinks. See https://github.com/bazelbuild/bazel/issues/16361.
168179
target_triplet = cc_toolchain_info_support.get_apple_clang_triplet(cc_toolchain)
@@ -280,6 +291,13 @@ def _apple_static_framework_import_impl(ctx):
280291
sdk_frameworks = ctx.attr.sdk_frameworks
281292
weak_sdk_frameworks = ctx.attr.weak_sdk_frameworks
282293

294+
secure_features_support.validate_expected_secure_features(
295+
disabled_features = disabled_features,
296+
expected_secure_features = ctx.attr.expected_secure_features,
297+
features = features,
298+
rule_label = label,
299+
)
300+
283301
providers = [
284302
DefaultInfo(runfiles = ctx.runfiles(files = ctx.files.data)),
285303
]
@@ -413,9 +431,16 @@ apple_dynamic_framework_import = rule(
413431
attrs = dicts.add(
414432
rule_attrs.common_tool_attrs(),
415433
{
416-
# TODO: b/449684779 - Add an "expected_secure_features" attribute to declare what
417-
# features are expected to be present in the precompiled framework, so the rules can
418-
# validate against that and set required entitlements if necessary.
434+
"expected_secure_features": attr.string_list(
435+
doc = """
436+
A list of strings representing the secure features that are expected to be present in the
437+
precompiled framework. This is used to validate that the framework was built with Enhanced Security
438+
features matching those of its consumers on Apple platforms, through a "scout's honor" system.
439+
440+
This does not actually set the features on the precompiled artifacts, this merely acts as a
441+
"checklist" for the consuming targets to verify what they are expecting to be present.
442+
""",
443+
),
419444
"framework_imports": attr.label_list(
420445
allow_empty = False,
421446
allow_files = True,
@@ -485,9 +510,16 @@ apple_static_framework_import = rule(
485510
attrs = dicts.add(
486511
rule_attrs.common_tool_attrs(),
487512
{
488-
# TODO: b/449684779 - Add an "expected_secure_features" attribute to declare what
489-
# features are expected to be present in the precompiled framework, so the rules can
490-
# validate against that and set required entitlements if necessary.
513+
"expected_secure_features": attr.string_list(
514+
doc = """
515+
A list of strings representing the secure features that are expected to be present in the
516+
precompiled framework. This is used to validate that the framework was built with Enhanced Security
517+
features matching those of its consumers on Apple platforms, through a "scout's honor" system.
518+
519+
This does not actually set the features on the precompiled artifacts, this merely acts as a
520+
"checklist" for the consuming targets to verify what they are expecting to be present.
521+
""",
522+
),
491523
"framework_imports": attr.label_list(
492524
allow_empty = False,
493525
allow_files = True,

apple/internal/apple_xcframework_import.bzl

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ load(
4949
"new_appledynamicframeworkinfo",
5050
)
5151
load("//apple/internal:rule_attrs.bzl", "rule_attrs")
52+
load(
53+
"//apple/internal:secure_features_support.bzl",
54+
"secure_features_support",
55+
)
5256
load(
5357
"//apple/internal/aspects:swift_usage_aspect.bzl",
5458
"SwiftUsageInfo",
@@ -490,6 +494,13 @@ def _apple_dynamic_xcframework_import_impl(ctx):
490494
xcframework_imports = ctx.files.xcframework_imports
491495
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
492496

497+
secure_features_support.validate_expected_secure_features(
498+
disabled_features = disabled_features,
499+
expected_secure_features = ctx.attr.expected_secure_features,
500+
features = features,
501+
rule_label = label,
502+
)
503+
493504
# TODO(b/258492867): Add tree artifacts support when Bazel can handle remote actions with
494505
# symlinks. See https://github.com/bazelbuild/bazel/issues/16361.
495506
target_triplet = cc_toolchain_info_support.get_apple_clang_triplet(cc_toolchain)
@@ -604,6 +615,13 @@ def _apple_static_xcframework_import_impl(ctx):
604615
xcframework_imports = ctx.files.xcframework_imports
605616
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
606617

618+
secure_features_support.validate_expected_secure_features(
619+
disabled_features = disabled_features,
620+
expected_secure_features = ctx.attr.expected_secure_features,
621+
features = features,
622+
rule_label = label,
623+
)
624+
607625
xcframework = _classify_xcframework_imports(ctx.var, xcframework_imports)
608626
target_triplet = cc_toolchain_info_support.get_apple_clang_triplet(cc_toolchain)
609627

@@ -753,9 +771,6 @@ objc_library(
753771
attrs = dicts.add(
754772
rule_attrs.common_tool_attrs(),
755773
{
756-
# TODO: b/449684779 - Add an "expected_secure_features" attribute to declare what
757-
# features are expected to be present in the precompiled framework, so the rules can
758-
# validate against that and set required entitlements if necessary.
759774
"xcframework_imports": attr.label_list(
760775
allow_empty = False,
761776
allow_files = True,
@@ -776,6 +791,17 @@ linked into that target.
776791
],
777792
aspects = [swift_clang_module_aspect],
778793
),
794+
"expected_secure_features": attr.string_list(
795+
doc = """
796+
A list of strings representing the secure features that are expected to be present in the
797+
precompiled XCFramework. This is used to validate that the XCFramework was built with Enhanced
798+
Security features matching those of its consumers on Apple platforms, through a "scout's honor"
799+
system.
800+
801+
This does not actually set the features on the precompiled artifacts, this merely acts as a
802+
"checklist" for the consuming targets to verify what they are expecting to be present.
803+
""",
804+
),
779805
"bundle_only": attr.bool(
780806
default = False,
781807
doc = """
@@ -829,9 +855,6 @@ objc_library(
829855
attrs = dicts.add(
830856
rule_attrs.common_tool_attrs(),
831857
{
832-
# TODO: b/449684779 - Add an "expected_secure_features" attribute to declare what
833-
# features are expected to be present in the precompiled framework, so the rules can
834-
# validate against that and set required entitlements if necessary.
835858
"alwayslink": attr.bool(
836859
default = False,
837860
doc = """
@@ -861,6 +884,17 @@ List of files needed by this target at runtime.
861884
Files and targets named in the `data` attribute will appear in the `*.runfiles`
862885
area of this target, if it has one. This may include data files needed by a
863886
binary or library, or other programs needed by it.
887+
""",
888+
),
889+
"expected_secure_features": attr.string_list(
890+
doc = """
891+
A list of strings representing the secure features that are expected to be present in the
892+
precompiled XCFramework. This is used to validate that the XCFramework was built with Enhanced
893+
Security features matching those of its consumers on Apple platforms, through a "scout's honor"
894+
system.
895+
896+
This does not actually set the features on the precompiled artifacts, this merely acts as a
897+
"checklist" for the consuming targets to verify what they are expecting to be present.
864898
""",
865899
),
866900
"has_swift": attr.bool(

apple/internal/secure_features_support.bzl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,39 @@ def _environment_archs_from_secure_features(
202202
return other_archs
203203
return arm64e_archs + other_archs
204204

205+
def _validate_expected_secure_features(
206+
*,
207+
disabled_features,
208+
expected_secure_features,
209+
features,
210+
rule_label):
211+
# Ignoring cc_common verification against the cc_toolchain this time as this method is expected
212+
# to be used exclusively by library-level dependencies of an Apple rule; ctx.features and
213+
# ctx.disabled_features are the best proxies at this point.
214+
requested_features = set(features) - set(disabled_features)
215+
requested_secure_features = requested_features & _SUPPORTED_SECURE_FEATURES
216+
if not requested_secure_features:
217+
return
218+
219+
missing_expected_secure_features = requested_secure_features - set(expected_secure_features)
220+
221+
if missing_expected_secure_features:
222+
fail(
223+
"""
224+
The precompiled artifact at `{rule_label}` was expected to be compatible with the following secure \
225+
features requested from the build, but they were not indicated as supported by the target's \
226+
`expected_secure_features` attribute:
227+
- {missing_secure_features}
228+
229+
Please contact the owner of this target to supply a precompiled artifact (likely a framework or \
230+
XCFramework) that is built with the required Enhanced Security features enabled, and update the \
231+
"expected_secure_features" attribute to match.
232+
""".format(
233+
rule_label = str(rule_label),
234+
missing_secure_features = "\n- ".join(list(missing_expected_secure_features)),
235+
),
236+
)
237+
205238
def _validate_secure_features_support(
206239
*,
207240
cc_configured_features_init,
@@ -263,5 +296,6 @@ secure_features_support = struct(
263296
entitlements_from_secure_features = _entitlements_from_secure_features,
264297
environment_arch_specific_features = _environment_arch_specific_features,
265298
environment_archs_from_secure_features = _environment_archs_from_secure_features,
299+
validate_expected_secure_features = _validate_expected_secure_features,
266300
validate_secure_features_support = _validate_secure_features_support,
267301
)

test/starlark_tests/apple_dynamic_xcframework_import_tests.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,26 @@ def apple_dynamic_xcframework_import_test_suite(name):
485485
tags = [name],
486486
)
487487

488+
analysis_failure_message_test(
489+
name = "{}_secure_features_app_fails_importing_xcframework_with_no_expected_secure_features_test".format(name),
490+
target_under_test = "//test/starlark_tests/targets_under_test/ios:secure_features_app_with_imported_dynamic_xcframework_and_no_expected_secure_features",
491+
expected_error = """The precompiled artifact at `//test/starlark_tests/targets_under_test/ios:ios_imported_dynamic_xcframework_with_missing_pointer_authentication_secure_features` was expected to be compatible with the following secure features requested from the build, but they were not indicated as supported by the target's `expected_secure_features` attribute:
492+
- apple.xcode_26_minimum_opt_in
493+
494+
Please contact the owner of this target to supply a precompiled artifact (likely a framework or XCFramework) that is built with the required Enhanced Security features enabled, and update the "expected_secure_features" attribute to match.""",
495+
tags = [name],
496+
)
497+
498+
analysis_failure_message_test(
499+
name = "{}_secure_features_app_fails_importing_xcframework_with_mismatched_secure_features_test".format(name),
500+
target_under_test = "//test/starlark_tests/targets_under_test/ios:secure_features_app_with_imported_dynamic_xcframework_and_mismatched_secure_features",
501+
expected_error = """The precompiled artifact at `//test/starlark_tests/targets_under_test/ios:ios_imported_dynamic_xcframework` was expected to be compatible with the following secure features requested from the build, but they were not indicated as supported by the target's `expected_secure_features` attribute:
502+
- trivial_auto_var_init
503+
504+
Please contact the owner of this target to supply a precompiled artifact (likely a framework or XCFramework) that is built with the required Enhanced Security features enabled, and update the "expected_secure_features" attribute to match.""",
505+
tags = [name],
506+
)
507+
488508
native.test_suite(
489509
name = name,
490510
tags = [name],

test/starlark_tests/apple_static_xcframework_import_tests.bzl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ load(
1818
"//apple/build_settings:build_settings.bzl",
1919
"build_settings_labels",
2020
)
21+
load(
22+
"//test/starlark_tests/rules:analysis_failure_message_test.bzl",
23+
"analysis_failure_message_test",
24+
)
2125
load(
2226
"//test/starlark_tests/rules:analysis_target_actions_test.bzl",
2327
"analysis_contains_xcframework_processor_action_test",
@@ -278,6 +282,27 @@ def apple_static_xcframework_import_test_suite(name):
278282
tags = [name],
279283
)
280284

285+
analysis_failure_message_test(
286+
name = "{}_secure_features_app_fails_importing_xcframework_with_no_expected_secure_features_test".format(name),
287+
target_under_test = "//test/starlark_tests/targets_under_test/ios:secure_features_app_with_imported_static_xcframework_and_no_expected_secure_features",
288+
expected_error = """The precompiled artifact at `//test/starlark_tests/targets_under_test/ios:ios_imported_static_xcframework_with_missing_pointer_authentication_secure_features` was expected to be compatible with the following secure features requested from the build, but they were not indicated as supported by the target's `expected_secure_features` attribute:
289+
- apple.xcode_26_minimum_opt_in
290+
291+
Please contact the owner of this target to supply a precompiled artifact (likely a framework or XCFramework) that is built with the required Enhanced Security features enabled, and update the "expected_secure_features" attribute to match.""",
292+
tags = [name],
293+
)
294+
295+
analysis_failure_message_test(
296+
name = "{}_secure_features_app_fails_importing_xcframework_with_mismatched_secure_features_test".format(name),
297+
target_under_test = "//test/starlark_tests/targets_under_test/ios:secure_features_app_with_imported_static_xcframework_and_mismatched_secure_features",
298+
expected_error = """The precompiled artifact at `//test/starlark_tests/targets_under_test/ios:ios_imported_static_xcframework` was expected to be compatible with the following secure features requested from the build, but they were not indicated as supported by the target's `expected_secure_features` attribute:
299+
- trivial_auto_var_init
300+
301+
Please contact the owner of this target to supply a precompiled artifact (likely a framework or XCFramework) that is built with the required Enhanced Security features enabled, and update the "expected_secure_features" attribute to match.
302+
""",
303+
tags = [name],
304+
)
305+
281306
native.test_suite(
282307
name = name,
283308
tags = [name],

0 commit comments

Comments
 (0)