xref: /trunk/test/odf-validate/make-pkg-controls.py (revision 0e16a31d78a652c56c5c0fc79c752f48b9048df9)
1*0e16a31dSJim Jagielski#**************************************************************
2*0e16a31dSJim Jagielski#
3*0e16a31dSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*0e16a31dSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*0e16a31dSJim Jagielski#  distributed with this work for additional information
6*0e16a31dSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*0e16a31dSJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*0e16a31dSJim Jagielski#  "License"); you may not use this file except in compliance
9*0e16a31dSJim Jagielski#  with the License.  You may obtain a copy of the License at
10*0e16a31dSJim Jagielski#
11*0e16a31dSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*0e16a31dSJim Jagielski#
13*0e16a31dSJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*0e16a31dSJim Jagielski#  software distributed under the License is distributed on an
15*0e16a31dSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*0e16a31dSJim Jagielski#  KIND, either express or implied.  See the License for the
17*0e16a31dSJim Jagielski#  specific language governing permissions and limitations
18*0e16a31dSJim Jagielski#  under the License.
19*0e16a31dSJim Jagielski#
20*0e16a31dSJim Jagielski#**************************************************************
21*0e16a31dSJim Jagielski
22*0e16a31dSJim Jagielski# usage: make-pkg-controls.py -- (re)generate pkgcheck.py's negative-control packages in fixtures/control-pkg/
23*0e16a31dSJim Jagielski# .expected.json maps each package to the (level, rule) pairs pkgcheck.py must report, exactly.
24*0e16a31dSJim Jagielskiimport json, os, shutil, warnings, zipfile
25*0e16a31dSJim Jagielski
26*0e16a31dSJim JagielskiC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "control-pkg")
27*0e16a31dSJim JagielskiMIME = "application/vnd.oasis.opendocument.text"
28*0e16a31dSJim JagielskiS, Z = zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED
29*0e16a31dSJim JagielskiSIG = ('<?xml version="1.0" encoding="UTF-8"?>\n<dsig:document-signatures xmlns:dsig="urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0" '
30*0e16a31dSJim Jagielski       'dsig:version="%s" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:Signature Id="s1"/></dsig:document-signatures>\n')
31*0e16a31dSJim JagielskiENC = ('<manifest:encryption-data manifest:checksum-type="SHA1/1K" manifest:checksum="AAAA">'
32*0e16a31dSJim Jagielski       '<manifest:algorithm manifest:algorithm-name="Blowfish CFB" manifest:initialisation-vector="AAAA"/>'
33*0e16a31dSJim Jagielski       '<manifest:key-derivation manifest:key-derivation-name="PBKDF2" manifest:key-size="16" manifest:iteration-count="1024" manifest:salt="AAAA"/>'
34*0e16a31dSJim Jagielski       '</manifest:encryption-data>')
35*0e16a31dSJim Jagielski
36*0e16a31dSJim Jagielski
37*0e16a31dSJim Jagielskidef entry(path, mt="text/xml", inner="", **attrs):
38*0e16a31dSJim Jagielski    a = "".join(' manifest:%s="%s"' % kv for kv in attrs.items())
39*0e16a31dSJim Jagielski    return '<manifest:file-entry manifest:full-path="%s" manifest:media-type="%s"%s>%s</manifest:file-entry>' % (path, mt, a, inner)
40*0e16a31dSJim Jagielski
41*0e16a31dSJim Jagielski
42*0e16a31dSJim Jagielskidef manifest(*entries, root="manifest:manifest"):
43*0e16a31dSJim Jagielski    return ('<?xml version="1.0" encoding="UTF-8"?>\n<%s xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">%s</%s>\n'
44*0e16a31dSJim Jagielski            % (root, "".join(entries), root))
45*0e16a31dSJim Jagielski
46*0e16a31dSJim Jagielski
47*0e16a31dSJim JagielskiROOT = entry("/", MIME, version="1.2")
48*0e16a31dSJim JagielskiCONTENT = entry("content.xml")
49*0e16a31dSJim JagielskiGOOD_MANI = manifest(ROOT, CONTENT)
50*0e16a31dSJim JagielskiEXPECTED = {}
51*0e16a31dSJim Jagielski
52*0e16a31dSJim Jagielski
53*0e16a31dSJim Jagielskidef build(name, files, expect=()):
54*0e16a31dSJim Jagielski    """files: (zip name, data, method[, extra]) in physical order."""
55*0e16a31dSJim Jagielski    with zipfile.ZipFile(os.path.join(C, name + ".odt"), "w") as z, warnings.catch_warnings():
56*0e16a31dSJim Jagielski        warnings.simplefilter("ignore")
57*0e16a31dSJim Jagielski        for f in files:
58*0e16a31dSJim Jagielski            zi = zipfile.ZipInfo(f[0])
59*0e16a31dSJim Jagielski            if len(f) > 3:
60*0e16a31dSJim Jagielski                zi.extra = f[3]
61*0e16a31dSJim Jagielski            z.writestr(zi, f[1], compress_type=f[2])
62*0e16a31dSJim Jagielski    EXPECTED[name + ".odt"] = sorted(expect)
63*0e16a31dSJim Jagielski
64*0e16a31dSJim Jagielski
65*0e16a31dSJim Jagielskidef std(mani=GOOD_MANI, mime=MIME, extra=()):
66*0e16a31dSJim Jagielski    return [("mimetype", mime, S), ("content.xml", "<c/>", Z)] + list(extra) + [("META-INF/manifest.xml", mani, Z)]
67*0e16a31dSJim Jagielski
68*0e16a31dSJim Jagielski
69*0e16a31dSJim Jagielskishutil.rmtree(C, ignore_errors=True)
70*0e16a31dSJim Jagielskios.makedirs(C)
71*0e16a31dSJim Jagielskibuild("good", std())
72*0e16a31dSJim Jagielskisub = [("Object 1/content.xml", "<c/>", Z), ("Pictures/a.png", "x", S), ("secret.xml", "0123456789", S),
73*0e16a31dSJim Jagielski       ("META-INF/documentsignatures.xml", SIG % "1.2", Z)]
74*0e16a31dSJim Jagielskibuild("good-full", std(manifest(ROOT, CONTENT, entry("Object 1/", MIME, version="1.2"), entry("Object 1/content.xml"),
75*0e16a31dSJim Jagielski                                entry("Pictures/a.png", "image/png"), entry("secret.xml", inner=ENC, size="10")), extra=sub))
76*0e16a31dSJim Jagielskibuild("mime-deflated", [("mimetype", MIME, Z), ("content.xml", "<c/>", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-compressed")])
77*0e16a31dSJim Jagielskibuild("mime-extra", [("mimetype", MIME, S, b"\xfe\xca\x00\x00"), ("content.xml", "<c/>", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-extra")])
78*0e16a31dSJim Jagielskibuild("mime-notfirst", [("content.xml", "<c/>", Z), ("mimetype", MIME, S), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-first")])
79*0e16a31dSJim Jagielskibuild("mime-mismatch", std(mime="application/x-bogus"), [("shall", "mimetype-mismatch")])
80*0e16a31dSJim Jagielskibuild("mime-nonascii", std(mime=MIME + "é"), [("shall", "mimetype-ascii")])
81*0e16a31dSJim Jagielskibuild("mime-missing", std()[1:], [("should", "mimetype-missing"), ("shall", "mimetype-missing")])
82*0e16a31dSJim Jagielskibuild("mime-missing-noroot", std(manifest(CONTENT))[1:], [("should", "mimetype-missing")])
83*0e16a31dSJim Jagielskibuild("no-root-entry", std(manifest(CONTENT)), [("shall", "manifest-root-entry")])
84*0e16a31dSJim Jagielskibuild("uncovered", std(extra=[("extra.xml", "<e/>", Z)]), [("shall", "manifest-coverage")])
85*0e16a31dSJim Jagielskibuild("dup-entry", std(manifest(ROOT, CONTENT, CONTENT)), [("shall", "manifest-duplicate")])
86*0e16a31dSJim Jagielskibuild("self-entry", std(manifest(ROOT, CONTENT, entry("mimetype", "text/plain"))), [("shall", "manifest-self")])
87*0e16a31dSJim Jagielskibuild("dangling", std(manifest(ROOT, CONTENT, entry("gone.xml"))), [("should", "manifest-dangling")])
88*0e16a31dSJim Jagielskibuild("dir-entry-manifest", std(manifest(ROOT, CONTENT, entry("Configurations2/", "application/vnd.sun.xml.ui.configuration"))), [("should", "manifest-dir-entry")])
89*0e16a31dSJim Jagielskibuild("stray-meta-inf", std(extra=[("META-INF/foo.xml", "<f/>", Z)]), [("shall", "meta-inf-file")])
90*0e16a31dSJim Jagielskibuild("no-manifest", [("mimetype", MIME, S), ("content.xml", "<c/>", Z)], [("shall", "manifest-missing")])
91*0e16a31dSJim Jagielskibuild("manifest-malformed", std("<manifest:manifest"), [("shall", "manifest-malformed")])
92*0e16a31dSJim Jagielskibuild("manifest-wrongroot", std(manifest(root="manifest:other")), [("shall", "manifest-root")])
93*0e16a31dSJim Jagielskibuild("zip-bzip2", std(extra=[("b.xml", "<b/>", zipfile.ZIP_BZIP2)], mani=manifest(ROOT, CONTENT, entry("b.xml"))), [("shall", "zip-method")])
94*0e16a31dSJim Jagielskibuild("zip-dup-name", std(extra=[("content.xml", "<d/>", Z)]), [("shall", "zip-duplicate")])
95*0e16a31dSJim Jagielskibuild("zip-dir-entry", std(extra=[("Pictures/", "", S)]), [("should", "zip-dir-entry")])
96*0e16a31dSJim Jagielskibuild("enc-nosize", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC)), extra=[("secret.xml", "0123456789", S)]), [("shall", "encrypted-size")])
97*0e16a31dSJim Jagielskibuild("enc-deflated", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC, size="10")), extra=[("secret.xml", "0123456789", Z)]), [("shall", "encrypted-method")])
98*0e16a31dSJim Jagielskibuild("sig-malformed", std(extra=[("META-INF/documentsignatures.xml", "<dsig", Z)]), [("shall", "signature-malformed")])
99*0e16a31dSJim Jagielskibuild("sig-wrongroot", std(extra=[("META-INF/documentsignatures.xml", "<a/>", Z)]), [("shall", "signature-root")])
100*0e16a31dSJim Jagielskibuild("sig-badversion", std(extra=[("META-INF/documentsignatures.xml", SIG % "1.1", Z)]), [("shall", "signature-schema")])
101*0e16a31dSJim Jagielskijson.dump(EXPECTED, open(os.path.join(C, ".expected.json"), "w"), indent=1)
102