1#!/usr/bin/env python3

2# Copyright 2020 Canonical Ltd.

3# All rights reserved.

4#

5# Written by:

6# Jonathan Cave <jonathan.cave@canonical.com>

7

8 import io

9 import os

10 import sys

11

12 from checkbox_support.snap_utils.snapd import Snapd

13

14

15 class SnapInfo:

16

17 def __init__(self):

18 self.kernel = None

19 self.gadget = None

20 data = Snapd().list()

21 for snap in data:

22 if snap["type"] == "kernel":

23 self.kernel = snap

24 if snap["type"] == "gadget":

25 self.gadget = snap

26

27 def test_kernel_publisher(self):

28 if not self.kernel:

29 raise SystemExit("ERROR: failed to get kernel snap info")

30 if self.kernel["publisher"]["id"] != "canonical":

31 raise SystemExit("ERROR: kernel snap publisher must be canonical")

32 if self.kernel["publisher"]["validation"] != "verified":

33 raise SystemExit("ERROR: kernel snap publisher must be verified")

34 print("PASS")

35

36 def test_kernel_tracking(self):

37 if not self.kernel:

38 raise SystemExit("ERROR: failed to get kernel snap info")

39 if not self.kernel.get("tracking-channel"):

40 raise SystemExit("ERROR: kernel must be tracking a store channel")

41 if "stable" not in self.kernel["tracking-channel"]:

42 raise SystemExit("ERROR: kernel must be on a stable channel")

43 print("PASS")

44

45 def test_gadget_publisher(self):

46 if not self.gadget:

47 raise SystemExit("ERROR: failed to get gadget snap info")

48 if self.gadget["publisher"]["id"] != "canonical":

49 raise SystemExit("ERROR: gadget snap publisher must be canonical")

50 if self.gadget["publisher"]["validation"] != "verified":

51 raise SystemExit("ERROR: gadget snap publisher must be verified")

52 print("PASS")

53

54 def test_gadget_tracking(self):

55 if not self.gadget:

56 raise SystemExit("ERROR: failed to get gadget snap info")

57 if not self.gadget.get("tracking-channel"):

58 raise SystemExit("ERROR: gadget must be tracking a store channel")

59 if "stable" not in self.gadget["tracking-channel"]:

60 raise SystemExit("ERROR: gadget must be on a stable channel")

61 print("PASS")

62

63

64 class ModelInfo:

65

66 def __init__(self):

67 self.authority = None

68 self.brand = None

69 self.grade = None

70 for line in io.StringIO(Snapd().get_assertions("model").text):

71 if ":" in line:

72 entry = line.split(":", maxsplit=1)

73 if entry[0] == "authority-id":

74 self.authority = entry[1].strip()

75 if entry[0] == "brand-id":

76 self.brand = entry[1].strip()

77 if entry[0] == "grade":

78 self.grade = entry[1].strip()

79

80 def test_model_authority(self):

81 if not self.authority:

82 raise SystemExit("ERROR: failed to get model authority info")

83 if self.authority != "canonical":

84 raise SystemExit("ERROR: model authority must be canonical")

85 print("PASS")

86

87 def test_model_brand(self):

88 if not self.brand:

89 raise SystemExit("ERROR: failed to get model brand info")

90 if self.brand != "canonical":

91 raise SystemExit("ERROR: model brand must be canonical")

92 print("PASS")

93

94 def test_model_grade(self):

95 MODEL_GRADE = os.environ.get("MODEL_GRADE", "secured")

96 if not self.grade:

97 raise SystemExit("ERROR: failed to get model grade info")

98 if self.grade == "dangerous":

99 raise SystemExit("ERROR: model grade must not be dangerous")

100 if self.grade != MODEL_GRADE:

101 raise SystemExit(

102 'ERROR: model grade is "{}",'.format(self.grade)

103 + ' but "{}" is expected'.format(MODEL_GRADE)

104 )

105 print("PASS")

106

107

108 def main():

109 if len(sys.argv) != 2:

110 raise SystemExit("USAGE: ubuntucore_image_checks.py [action]")

111 action = sys.argv[1]

112

113 snapinfo = SnapInfo()

114 modelinfo = ModelInfo()

115

116 if action == "kernel-publisher":

117 snapinfo.test_kernel_publisher()

118 elif action == "kernel-tracking":

119 snapinfo.test_kernel_tracking()

120 elif action == "gadget-publisher":

121 snapinfo.test_gadget_publisher()

122 elif action == "gadget-tracking":

123 snapinfo.test_gadget_tracking()

124 elif action == "model-authority":

125 modelinfo.test_model_authority()

126 elif action == "model-brand":

127 modelinfo.test_model_brand()

128 elif action == "model-grade":

129 modelinfo.test_model_grade()

130 else:

131 raise SystemExit("ERROR: unrecognised action")

132

133

134 if __name__ == "__main__":

135 main()