1# Copyright (C) 2022 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load(":env_variables.bzl", _CAPTURED_ENV_VARS = "CAPTURED_ENV_VARS")
16
17_ALLOWED_SPECIAL_CHARACTERS = [
18    "/",
19    "_",
20    "-",
21    "'",
22    ".",
23    " ",
24]
25
26# Since we write the env var value literally into a .bzl file, ensure that the string
27# does not contain special characters like '"', '\n' and '\'. Use an allowlist approach
28# and check that the remaining string is alphanumeric.
29def _validate_env_value(env_var, env_value):
30    if env_value == "":
31        return
32    sanitized_env_value = env_value
33    for allowed_char in _ALLOWED_SPECIAL_CHARACTERS:
34        sanitized_env_value = sanitized_env_value.replace(allowed_char, "")
35    if not sanitized_env_value.isalnum():
36        fail("The value of " +
37             env_var +
38             " can only consist of alphanumeric and " +
39             str(_ALLOWED_SPECIAL_CHARACTERS) +
40             " characters: " +
41             str(env_value))
42
43def _env_impl(rctx):
44    captured_env = {}
45    for var in _CAPTURED_ENV_VARS:
46        value = rctx.os.environ.get(var)
47        if value != None:
48            _validate_env_value(var, value)
49            captured_env[var] = value
50
51    rctx.file("BUILD.bazel", """
52exports_files(["env.bzl"])
53""")
54
55    rctx.file("env.bzl", """
56env = {
57    %s
58}
59""" % "\n    ".join([
60        '"%s": "%s",' % (var, value)
61        for var, value in captured_env.items()
62    ]))
63
64env_repository = repository_rule(
65    implementation = _env_impl,
66    configure = True,
67    local = True,
68    environ = _CAPTURED_ENV_VARS,
69    doc = "A repository rule to capture environment variables.",
70)
71