# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import getpass import json import logging import os import re import subprocess import urllib.error import urllib.request
import yaml from mach.decorators import Command, CommandArgument from mach.util import UserError
def get_blocking_bug():
securitydir = os.path.dirname(__file__) with open(os.path.join(securitydir, "nss", "moz.yaml")) as f:
manifest = yaml.load(f, Loader=yaml.BaseLoader) if"updatebot"notin manifest: raise UserError("moz.yaml must have an updatebot section")
updatebot = manifest["updatebot"] if"tasks"notin manifest["updatebot"]: raise UserError("updatebot section of moz.yaml must have tasks")
tasks = updatebot["tasks"]
vendoring_task = [
task for task in tasks if"type"in task and task["type"] == "vendoring"
] if len(vendoring_task) != 1: raise UserError( "updatebot section of moz.yaml must have exactly one vendoring task"
)
vendoring_task = vendoring_task[0] if"blocking"notin vendoring_task: raise UserError( "vendoring task of updatebot section of moz.yaml must have a blocking bug"
) return vendoring_task["blocking"]
def next_nss_version(tag): """Convert the NSS version tag to the next dotted version, e.g. 'NSS_3_123_RTM' to '3.124'.""" ifnot (tag.startswith("NSS_") and tag.endswith("_RTM")): returnNone
parts = tag[4:-4].rsplit("_", 1) # ["3", "123"] if len(parts) != 2: returnNone try: return f"{parts[0]}.{int(parts[1]) + 1}" except ValueError: returnNone
def next_firefox_version():
securitydir = os.path.dirname(__file__)
version_path = os.path.join(securitydir, "..", "browser", "config", "version.txt") with open(version_path) as f:
version = f.read().strip() return str(int(version.split(".")[0]) + 1)
def create_next_nss_uplift_bug(bug, api_key):
data = json.dumps(bug).encode("utf-8")
req = urllib.request.Request(BUGZILLA_API_URL, data=data, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("X-BUGZILLA-API-KEY", api_key) try: with urllib.request.urlopen(req) as resp: return json.loads(resp.read())["id"] except urllib.error.HTTPError as e: raise UserError(f"Bugzilla API error {e.code}: {e.read().decode()}") from e
def update_blocking_bug(old_bug_id, new_bug_id):
securitydir = os.path.dirname(__file__)
moz_yaml_path = os.path.join(securitydir, "nss", "moz.yaml") with open(moz_yaml_path) as f:
content = f.read()
updated = re.sub(
rf"(blocking:\s*){re.escape(str(old_bug_id))}\b",
rf"\g<1>{new_bug_id}",
content,
) if updated == content: raise UserError("Could not find blocking bug number in moz.yaml to update") with open(moz_yaml_path, "w") as f:
f.write(updated)
@Command( "nss-uplift",
category="devenv",
description="Upgrade to a tagged release of NSS",
)
@CommandArgument( "tag",
nargs=1,
help="The tagged release or commit to upgrade to.",
) def nss_uplift(command_context, tag):
tag = tag[0]
result = subprocess.run(
["git", "status", "--porcelain"], capture_output=True, text=True, check=True
) if result.stdout.strip(): raise UserError( "Working tree is not clean. Please commit or stash your changes."
)
result = subprocess.run(
["./mach", "vendor", "security/nss/moz.yaml", "--revision", tag], check=True
)
if tag.startswith("NSS_"): with open("security/nss/TAG-INFO", "w") as f:
f.write(tag)
result = subprocess.run(
["git", "status", "--porcelain"], capture_output=True, text=True, check=True
) assert result.returncode == 0 if".def"in result.stdout:
command_context.log(
logging.WARNING, "nss_uplift",
{}, "Changes in .def. We might have to change security/nss.symbols then manually",
)
blocking_bug = get_blocking_bug()
if"_RTM"in tag:
nss_version = next_nss_version(tag) if nss_version isNone: raise UserError(f"Could not parse NSS version from tag: {tag}")
fx_version = next_firefox_version()
bug = { "product": "Core", "component": "Security: PSM", "version": "unspecified", "summary": f"Upgrade Firefox {fx_version} to NSS {nss_version}", "type": "task", "priority": "P1", "severity": "N/A", "keywords": ["leave-open"], "blocks": [NSS_TRACKER_BUG],
}
print("\n" + "=" * 60)
print(json.dumps(bug, indent=2))
answer = input("Create this bug? [y/N] ").strip().lower()
print("=" * 60 + "\n") if answer notin ("y", "yes"):
command_context.log(
logging.WARNING, "nss_uplift",
{}, "Create a bug for the next release, update the blocking bug for updatebot in security/nss/moz.yaml, and commit your changes",
) return0
print( "Get an API key from https://bugzilla.mozilla.org/userprefs.cgi?tab=apikey"
)
api_key = getpass.getpass("Bugzilla API key: ") ifnot api_key:
command_context.log(
logging.WARNING, "nss_uplift", {}, "No API key provided"
) return1
new_bug_id = create_next_nss_uplift_bug(bug, api_key)
command_context.log(
logging.INFO, "nss_uplift",
{"bug_id": new_bug_id}, "Created bug {bug_id}: https://bugzilla.mozilla.org/{bug_id}",
)
update_blocking_bug(blocking_bug, new_bug_id)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.