diff options
author | Tony Aiuto <aiuto@google.com> | 2023-01-20 01:03:11 -0500 |
---|---|---|
committer | Tony Aiuto <aiuto@google.com> | 2023-01-20 01:03:11 -0500 |
commit | 8ec289604beb093bdb1b9ebc8465c5ec45ee93c0 (patch) | |
tree | 8acbe5fcfa489734ff5549b04bc69cb45d1db3fe | |
parent | 989ccbf8d64556d248b10d8797951bd03a9ea326 (diff) | |
download | bazelbuild-rules_license-8ec289604beb093bdb1b9ebc8465c5ec45ee93c0.tar.gz |
bring back the policy checker example
-rw-r--r-- | examples/policy_checker/BUILD | 63 | ||||
-rw-r--r-- | examples/policy_checker/license_policy.bzl | 56 | ||||
-rw-r--r-- | examples/policy_checker/license_policy_check.bzl | 94 | ||||
-rw-r--r-- | examples/policy_checker/license_policy_provider.bzl | 24 | ||||
-rw-r--r-- | examples/src/BUILD | 16 | ||||
-rw-r--r-- | examples/vendor/acme/BUILD | 5 | ||||
-rw-r--r-- | examples/vendor/libhhgttg/BUILD | 5 |
7 files changed, 261 insertions, 2 deletions
diff --git a/examples/policy_checker/BUILD b/examples/policy_checker/BUILD new file mode 100644 index 0000000..a18bcd2 --- /dev/null +++ b/examples/policy_checker/BUILD @@ -0,0 +1,63 @@ +# Example of automated license policy definitions. + +load("@rules_license//examples/policy_checker:license_policy.bzl", "license_policy") +load("@rules_license//examples/policy_checker:license_policy_check.bzl", "license_policy_check") + +package(default_package_metadata = ["//:license", "//:package_info"]) + +# license_policy rules generally appear in a central location per workspace. That +# should be access controlled by the policy team. + +# A production service can use licenses with most conditions +license_policy( + name = "production_service", + conditions = [ + "notice", + "restricted_if_statically_linked", + ], +) + +# A mobile application usually can not allow end-user replacable libraries. +# So LGPL code (which is restricted_if_statically_linked) can not be used. +license_policy( + name = "mobile_application", + conditions = [ + "notice", + ], +) + +license_policy( + name = "special_whitelisted_app", + # There could be a whitelist of targets here. + conditions = [ + "notice", + "whitelist:acme_corp_paid", + ], +) + +# Now we might build checks of critical applications against policies +# +# Questions to consider? +# - Your organization migth want to fold these kinds of checks into +# wrapper macros around the rules which generate services and apps +# - You might want to distribute checks to rules alongside the products +# - Or, you might want to consolidate them in a single place where your +# compliance team owns them, as this example does + +license_policy_check( + name = "check_server", + policy = ":production_service", + target = "//examples/src:my_server", +) + + +# This is marked manual, so bazel test ... does not fail. Try it yourself with +# bazel build :check_violating_server +license_policy_check( + name = "check_violating_server", + policy = ":production_service", + tags = [ + "manual", + ], + target = "//examples/src:my_violating_server", +) diff --git a/examples/policy_checker/license_policy.bzl b/examples/policy_checker/license_policy.bzl new file mode 100644 index 0000000..51d6776 --- /dev/null +++ b/examples/policy_checker/license_policy.bzl @@ -0,0 +1,56 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""license_policy rule. + +A license_policy names a set of conditions allowed in the union of all +license_kinds use by a target. The name of the rule is typically an +application type (e.g. production_server, mobile_application, ...) + +""" + +load( + "@rules_license//examples/policy_checker:license_policy_provider.bzl", + "LicensePolicyInfo" +) + +def _license_policy_impl(ctx): + provider = LicensePolicyInfo( + name = ctx.attr.name, + label = "@%s//%s:%s" % ( + ctx.label.workspace_name, + ctx.label.package, + ctx.label.name, + ), + conditions = ctx.attr.conditions, + ) + return [provider] + +_license_policy = rule( + implementation = _license_policy_impl, + attrs = { + "conditions": attr.string_list( + doc = "Conditions to be met when using software under this license." + + " Conditions are defined by the organization using this license.", + mandatory = True, + ), + }, +) + +def license_policy(name, conditions): + _license_policy( + name = name, + conditions = conditions, + applicable_licenses = [], + ) diff --git a/examples/policy_checker/license_policy_check.bzl b/examples/policy_checker/license_policy_check.bzl new file mode 100644 index 0000000..2692a01 --- /dev/null +++ b/examples/policy_checker/license_policy_check.bzl @@ -0,0 +1,94 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""License compliance checking at analysis time.""" + +load( + "@rules_license//examples/policy_checker:license_policy_provider.bzl", + "LicensePolicyInfo", +) +load( + "@rules_license//rules:gather_licenses_info.bzl", + "gather_licenses_info", +) +load( + "@rules_license//rules:providers.bzl", + "LicenseInfo", + "TransitiveLicensesInfo", +) + +# This is a crude example of the kind of thing which can be done. +def _license_policy_check_impl(ctx): + policy = ctx.attr.policy[LicensePolicyInfo] + allowed_conditions = policy.conditions + if TransitiveLicensesInfo in ctx.attr.target: + for license in ctx.attr.target[TransitiveLicensesInfo].licenses.to_list(): + for kind in license.license_kinds: + # print(kind.conditions) + for condition in kind.conditions: + if condition not in allowed_conditions: + fail("Condition %s violates policy %s" % ( + condition, + policy.label, + )) + + if LicenseInfo in ctx.attr.target: + for license in ctx.attr.target[LicenseInfo].licenses.to_list(): + print(license) + for kind in license.license_kinds: + # print(kind.conditions) + for condition in kind.conditions: + if condition not in allowed_conditions: + fail("Condition %s violates policy %s" % ( + condition, + policy.label, + )) + return [DefaultInfo()] + +_license_policy_check = rule( + implementation = _license_policy_check_impl, + doc = """Internal implementation method for license_policy_check().""", + attrs = { + "policy": attr.label( + doc = """Policy definition.""", + mandatory = True, + providers = [LicensePolicyInfo], + ), + "target": attr.label( + doc = """Target to collect LicenseInfo for.""", + aspects = [gather_licenses_info], + mandatory = True, + allow_single_file = True, + ), + }, +) + +def license_policy_check(name, target, policy, **kwargs): + """Checks a target against a policy. + + Args: + name: The target. + target: A target to test for compliance with a policy + policy: A rule providing LicensePolicyInfo. + **kwargs: other args. + + Usage: + + license_policy_check( + name = "license_info", + target = ":my_app", + policy = "//my_org/compliance/policies:mobile_application", + ) + """ + _license_policy_check(name = name, target = target, policy = policy, **kwargs) diff --git a/examples/policy_checker/license_policy_provider.bzl b/examples/policy_checker/license_policy_provider.bzl new file mode 100644 index 0000000..caecce8 --- /dev/null +++ b/examples/policy_checker/license_policy_provider.bzl @@ -0,0 +1,24 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""LicensePolicyProvider.""" + +LicensePolicyInfo = provider( + doc = """Declares a policy name and the license conditions allowable under it.""", + fields = { + "conditions": "List of conditions to be met when using this software.", + "label": "The full path to the license policy definition.", + "name": "License policy name", + }, +) diff --git a/examples/src/BUILD b/examples/src/BUILD index ecab5da..0bcb938 100644 --- a/examples/src/BUILD +++ b/examples/src/BUILD @@ -16,6 +16,11 @@ load("@rules_license//rules:compliance.bzl", "check_license", "licenses_used") load("@rules_license//examples/vendor/constant_gen:defs.bzl", "constant_gen") +package( + default_package_metadata = ["//:license", "//:package_info"], + default_visibility = ["//visibility:public"], +) + cc_binary( name = "my_server", srcs = ["server.cc"], @@ -59,3 +64,14 @@ py_test( "@rules_license//tests:license_test_utils", ], ) + +# This server uses something under a restricted license +cc_binary( + name = "my_violating_server", + srcs = ["server.cc"], + deps = [ + ":message", + "@rules_license//examples/vendor/acme", + "@rules_license//examples/vendor/libhhgttg", + ], +) diff --git a/examples/vendor/acme/BUILD b/examples/vendor/acme/BUILD index 814957d..2e98d98 100644 --- a/examples/vendor/acme/BUILD +++ b/examples/vendor/acme/BUILD @@ -15,7 +15,10 @@ load("@rules_license//rules:license.bzl", "license") -package(default_applicable_licenses = [":license"]) +package( + default_applicable_licenses = [":license"], + default_visibility = ["//visibility:public"], +) # The default license for an entire package is typically named "license". license( diff --git a/examples/vendor/libhhgttg/BUILD b/examples/vendor/libhhgttg/BUILD index 44d2d61..15c7655 100644 --- a/examples/vendor/libhhgttg/BUILD +++ b/examples/vendor/libhhgttg/BUILD @@ -18,7 +18,10 @@ load("@rules_license//rules:license.bzl", "license") # Using a package wide default ensure that all targets are associated with the # license. -package(default_applicable_licenses = [":license"]) +package( + default_applicable_licenses = [":license"], + default_visibility = ["//visibility:public"], +) # The default license for an entire package is typically named "license". license( |