aboutsummaryrefslogtreecommitdiff
path: root/examples/policy_checker
diff options
context:
space:
mode:
Diffstat (limited to 'examples/policy_checker')
-rw-r--r--examples/policy_checker/BUILD63
-rw-r--r--examples/policy_checker/license_policy.bzl56
-rw-r--r--examples/policy_checker/license_policy_check.bzl90
-rw-r--r--examples/policy_checker/license_policy_provider.bzl24
4 files changed, 233 insertions, 0 deletions
diff --git a/examples/policy_checker/BUILD b/examples/policy_checker/BUILD
new file mode 100644
index 0000000..49f77aa
--- /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_allowlisted_app",
+ # There could be a allowlist of targets here.
+ conditions = [
+ "notice",
+ "allowlist: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..bb35eee
--- /dev/null
+++ b/examples/policy_checker/license_policy_check.bzl
@@ -0,0 +1,90 @@
+# 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")
+load("@rules_license//rules/private:gathering_providers.bzl", "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():
+ 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",
+ },
+)