Commit d0706227 authored by Enrico Zini's avatar Enrico Zini
Browse files

Implemented details of keycheck requirement

parent f3acbab1
......@@ -418,8 +418,60 @@ class Requirement(models.Model):
"notes": notes,
}
def compute_status_keycheck(self):
notes = []
satisfied = True
keycheck_results = None
if not self.process.person.fpr:
notes.append(("error", "no key is configured for {}".format(self.process.person.lookup_key)))
satisfied = False
else:
from keyring.models import Key
try:
key = Key.objects.get_or_download(self.process.person.fpr)
except RuntimeError as e:
key = None
notes.append(("error", "cannot run keycheck: " + str(e)))
satisfied = False
if key is not None:
keycheck = key.keycheck()
uids = []
has_good_uid = False
for ku in keycheck.uids:
uids.append({
"name": ku.uid.name.replace("@", ", "),
"remarks": " ".join(sorted(ku.errors)) if ku.errors else "ok",
"sigs_ok": ku.sigs_ok,
"sigs_no_key": len(ku.sigs_no_key),
"sigs_bad": len(ku.sigs_bad)
})
if not ku.errors and len(ku.sigs_ok) >= 2:
has_good_uid = True
if not has_good_uid:
notes.append(("warn", "no UID found that fully satisfies requirements"))
satisfied = False
keycheck_results = {
"main": {
"remarks": " ".join(sorted(keycheck.errors)) if keycheck.errors else "ok",
},
"uids": uids,
"updated": key.check_sigs_updated,
}
if keycheck.errors:
notes.append(("warn", "key has issues " + keycheck["main"]["remarks"]))
satisfied = False
return {
"satisfied": satisfied,
"notes": notes,
"keycheck": keycheck_results,
}
#def compute_status_keycheck(self):
class AMAssignment(models.Model):
......
......@@ -6,3 +6,12 @@ form.inline-form {
margin: 0;
padding: 0;
}
ul.packed {
margin: 0;
}
td.keycheck_key {
font-size: small;
}
td.keycheck_uid {
font-size: small;
}
......@@ -20,10 +20,10 @@
<h1>{{type_desc}}</h1>
{% include "process/requirement_status_widget.html" %}
{% include explain_template with edit=False %}
{% include "process/requirement_status_widget.html" %}
<h2>Signed statements</h2>
{% include "process/statement_table_widget.html" %}
......
......@@ -20,10 +20,10 @@
<h1>{{type_desc}}</h1>
{% include "process/requirement_status_widget.html" %}
{% include explain_template with edit=False %}
{% include "process/requirement_status_widget.html" %}
<h2>Application Manager</h2>
<table>
......
......@@ -20,10 +20,10 @@
<h1>{{type_desc}}</h1>
{% include "process/requirement_status_widget.html" %}
{% include explain_template with edit=False %}
{% include "process/requirement_status_widget.html" %}
<h2>Signed statements</h2>
{% include "process/statement_table_widget.html" %}
......
......@@ -24,10 +24,53 @@
<p>TODO: explain rationale of keycheck, link to relevent bits</p>
<p>TODO: display the applicant keycheck output</p>
<h2>Keycheck results</h2>
<p>In the meantime, you can run <tt>keycheck.sh</tt> on your machine and
comment or approve here.</p>
{% if status.keycheck %}
<table class="personinfo">
<tbody>
<tr>
<th>OpenPGP fingerprint</th>
<td>{{person.fpr|fingerprint}}{% if "edit_ldap" in visit_perms %} (<a href="{% url 'fprs_person_list' key=person.lookup_key %}">manage</a>){% endif %}</td>
</tr>
{% with status.keycheck as keycheck %}
<tr>
<th>Main key</th>
<td class="keycheck_key">
<b>{{keycheck.main.remarks}}</b> (last updated: {{keycheck.updated|date:"Y-m-d H:i T"}})
{% if "update_keycheck" in visit_perms %}
<form class="inline" action="{% url 'process_update_keycheck' pk=process.pk %}" method="POST">{% csrf_token %}
<button type="submit">Update</button>
</form>
{% endif %}
</td>
</tr>
{% for uid in keycheck.uids %}
<tr>
<th>UID {{uid.name}}</th>
<td class="keycheck_uid">
<b>{{uid.remarks}}</b>, <i>{{uid.sigs_no_key}}</i> non-DD sigs,
{% if uid.sigs_ok|length > 10 %}
first 10 of <b>{{uid.sigs_ok|length}}</b> DD sigs:
{% else %}
<b>{{uid.sigs_ok|length}}</b> DD sigs:
{% endif %}
<ul class="packed">
{% for s in uid.sigs_ok|slice:":10" %}
<li>{{s.4}}: {{s.9}}</li>
{% empty %}
<li>none</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
{% endwith %}
</tbody>
</table>
{% else %}
<p>No keycheck results available</p>
{% endif %}
<h2>Log</h2>
......
......@@ -20,10 +20,10 @@
<h1>{{type_desc}}</h1>
{% include "process/requirement_status_widget.html" %}
{% include explain_template with edit=False %}
{% include "process/requirement_status_widget.html" %}
<h2>Signed statements</h2>
{% include "process/statement_table_widget.html" %}
......
{% if requirement.approved_by %}
<p><i>This requirement has been approved by <a href="{{requirement.approved_by.get_absolute_url}}">{{requirement.approved_by}}</a> {{requirement.approved_time|timesince}} ago.</i></p>
{% else %}
<p><i>This requirement has not been approved yet.</i></p>
{% if status.satisfied %}
<p><i>This requirement looks ready for approval, but has not been approved yet.</i></p>
{% else %}
<p><i>This requirement looks incomplete.</i></p>
{% endif %}
{% endif %}
{% if status.notes %}
<h3>Potential problems</h3>
<ul>
{% for nclass, ntext in status.notes %}
<li class="{{nclass}}">{{ntext}}</li>
{% endfor %}
</ul>
{% endif %}
......@@ -24,4 +24,5 @@ urlpatterns = [
url(r'^(?P<pk>\d+)/unassign_am$', views.UnassignAM.as_view(), name="process_unassign_am"),
url(r'^(?P<pk>\d+)/mailbox/download$', views.MailArchive.as_view(), name="process_mailbox_download"), # TODO: test
url(r'^(?P<pk>\d+)/mailbox$', views.DisplayMailArchive.as_view(), name="process_mailbox_show"), # TODO: test
url(r'^(?P<pk>\d+)/update_keycheck$', views.UpdateKeycheck.as_view(), name="process_update_keycheck"), # TODO: test
]
......@@ -175,6 +175,7 @@ class RequirementMixin(VisitProcessMixin):
ctx["type"] = self.requirement.type
ctx["type_desc"] = pmodels.REQUIREMENT_TYPES_DICT[self.requirement.type].desc
ctx["explain_template"] = "process/explain_statement_" + self.requirement.type + ".html"
ctx["status"] = self.requirement.compute_status()
return ctx
......@@ -403,3 +404,19 @@ class DisplayMailArchive(VisitProcessMixin, TemplateView):
ctx["process"] = process
ctx["class"] = "clickable"
return ctx
class UpdateKeycheck(RequirementMixin, View):
type = "keycheck"
require_visit_perms = "update_keycheck"
def post(self, request, *args, **kw):
from keyring.models import Key
try:
key = Key.objects.get_or_download(self.person.fpr)
except RuntimeError as e:
key = None
if key is not None:
key.update_key()
key.update_check_sigs()
return redirect(self.requirement.get_absolute_url())
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment