# 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 farbliche Syntaxdarstellung und die Messung sind noch experimentell.
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.