#**************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.
#
#**************************************************************
# usage: make-pkg-controls.py -- (re)generate pkgcheck.py's negative-control packages in fixtures/control-pkg/
# .expected.json maps each package to the (level, rule) pairs pkgcheck.py must report, exactly.
import json, os, shutil, warnings, zipfile
C = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "control-pkg")
MIME = "application/vnd.oasis.opendocument.text"
S, Z = zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED
SIG = ('\n\n')
ENC = (''
''
''
'')
def entry(path, mt="text/xml", inner="", **attrs):
a = "".join(' manifest:%s="%s"' % kv for kv in attrs.items())
return '%s' % (path, mt, a, inner)
def manifest(*entries, root="manifest:manifest"):
return ('\n<%s xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">%s%s>\n'
% (root, "".join(entries), root))
ROOT = entry("/", MIME, version="1.2")
CONTENT = entry("content.xml")
GOOD_MANI = manifest(ROOT, CONTENT)
EXPECTED = {}
def build(name, files, expect=()):
"""files: (zip name, data, method[, extra]) in physical order."""
with zipfile.ZipFile(os.path.join(C, name + ".odt"), "w") as z, warnings.catch_warnings():
warnings.simplefilter("ignore")
for f in files:
zi = zipfile.ZipInfo(f[0])
if len(f) > 3:
zi.extra = f[3]
z.writestr(zi, f[1], compress_type=f[2])
EXPECTED[name + ".odt"] = sorted(expect)
def std(mani=GOOD_MANI, mime=MIME, extra=()):
return [("mimetype", mime, S), ("content.xml", "", Z)] + list(extra) + [("META-INF/manifest.xml", mani, Z)]
shutil.rmtree(C, ignore_errors=True)
os.makedirs(C)
build("good", std())
sub = [("Object 1/content.xml", "", Z), ("Pictures/a.png", "x", S), ("secret.xml", "0123456789", S),
("META-INF/documentsignatures.xml", SIG % "1.2", Z)]
build("good-full", std(manifest(ROOT, CONTENT, entry("Object 1/", MIME, version="1.2"), entry("Object 1/content.xml"),
entry("Pictures/a.png", "image/png"), entry("secret.xml", inner=ENC, size="10")), extra=sub))
build("mime-deflated", [("mimetype", MIME, Z), ("content.xml", "", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-compressed")])
build("mime-extra", [("mimetype", MIME, S, b"\xfe\xca\x00\x00"), ("content.xml", "", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-extra")])
build("mime-notfirst", [("content.xml", "", Z), ("mimetype", MIME, S), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-first")])
build("mime-mismatch", std(mime="application/x-bogus"), [("shall", "mimetype-mismatch")])
build("mime-nonascii", std(mime=MIME + "é"), [("shall", "mimetype-ascii")])
build("mime-missing", std()[1:], [("should", "mimetype-missing"), ("shall", "mimetype-missing")])
build("mime-missing-noroot", std(manifest(CONTENT))[1:], [("should", "mimetype-missing")])
build("no-root-entry", std(manifest(CONTENT)), [("shall", "manifest-root-entry")])
build("uncovered", std(extra=[("extra.xml", "", Z)]), [("shall", "manifest-coverage")])
build("dup-entry", std(manifest(ROOT, CONTENT, CONTENT)), [("shall", "manifest-duplicate")])
build("self-entry", std(manifest(ROOT, CONTENT, entry("mimetype", "text/plain"))), [("shall", "manifest-self")])
build("dangling", std(manifest(ROOT, CONTENT, entry("gone.xml"))), [("should", "manifest-dangling")])
build("dir-entry-manifest", std(manifest(ROOT, CONTENT, entry("Configurations2/", "application/vnd.sun.xml.ui.configuration"))), [("should", "manifest-dir-entry")])
build("stray-meta-inf", std(extra=[("META-INF/foo.xml", "", Z)]), [("shall", "meta-inf-file")])
build("no-manifest", [("mimetype", MIME, S), ("content.xml", "", Z)], [("shall", "manifest-missing")])
build("manifest-malformed", std("", zipfile.ZIP_BZIP2)], mani=manifest(ROOT, CONTENT, entry("b.xml"))), [("shall", "zip-method")])
build("zip-dup-name", std(extra=[("content.xml", "", Z)]), [("shall", "zip-duplicate")])
build("zip-dir-entry", std(extra=[("Pictures/", "", S)]), [("should", "zip-dir-entry")])
build("enc-nosize", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC)), extra=[("secret.xml", "0123456789", S)]), [("shall", "encrypted-size")])
build("enc-deflated", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC, size="10")), extra=[("secret.xml", "0123456789", Z)]), [("shall", "encrypted-method")])
build("sig-malformed", std(extra=[("META-INF/documentsignatures.xml", "", Z)]), [("shall", "signature-root")])
build("sig-badversion", std(extra=[("META-INF/documentsignatures.xml", SIG % "1.1", Z)]), [("shall", "signature-schema")])
json.dump(EXPECTED, open(os.path.join(C, ".expected.json"), "w"), indent=1)