Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ietf/doc/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3648,8 +3648,23 @@ def test_obsoleted(self):
def test_generate_idnits2_rfc_status(self):
for slug in ('bcp', 'ds', 'exp', 'hist', 'inf', 'std', 'ps', 'unkn'):
WgRfcFactory(std_level_id=slug)
WgRfcFactory(rfc_number=10001, std_level_id='ps')
WgRfcFactory(rfc_number=10002, std_level_id=None)
blob = generate_idnits2_rfc_status().replace("\n", "")
self.assertEqual(blob[6312-1], "O")
# idnits2 discards the whole file if this is not "O" - see generate_idnits2_rfc_status
self.assertEqual(blob[16-1], "O")
self.assertEqual(blob[10001-1], "P")
self.assertEqual(blob[10002-1], "U")

def test_generate_idnits2_rfc_status_low_numbers_only(self):
# The workarounds write fixed offsets, so the blob has to reach 6312 even when
# no RFC does.
WgRfcFactory(rfc_number=1001, std_level_id="ps")
blob = generate_idnits2_rfc_status().replace("\n", "")
self.assertEqual(blob[6312-1], "O")
self.assertEqual(blob[200-1], "O")
self.assertEqual(blob[16-1], "O")

def test_rfc_status(self):
url = urlreverse('ietf.doc.views_doc.idnits2_rfc_status')
Expand Down
26 changes: 21 additions & 5 deletions ietf/doc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from django.conf import settings
from django.contrib import messages
from django.core.cache import caches
from django.db.models import OuterRef
from django.db.models import Max, OuterRef
from django.forms import ValidationError
from django.http import Http404
from django.template.loader import render_to_string
Expand Down Expand Up @@ -1386,8 +1386,6 @@ def update_doc_extresources(doc, new_resources, by):

def generate_idnits2_rfc_status():

blob=['N']*10000

symbols={
'ps': 'P',
'inf': 'I',
Expand All @@ -1399,10 +1397,17 @@ def generate_idnits2_rfc_status():
'unkn': 'U',
}

rfcs = Document.objects.filter(type_id='rfc')
rfcs = Document.objects.filter(type_id='rfc').exclude(rfc_number=None)

# One character per RFC number, indexed by that number, so the array has to reach the
# highest RFC published. The floor keeps the fixed offsets in the workarounds below in
# range when only a few RFCs exist, as is the case under test.
highest = rfcs.aggregate(Max('rfc_number'))['rfc_number__max'] or 0
blob=['N']*max(highest, 6312)

for rfc in rfcs:
offset = int(rfc.rfc_number)-1
blob[offset] = symbols[rfc.std_level_id]
blob[offset] = symbols.get(rfc.std_level_id, 'U')
if rfc.related_that('obs'):
blob[offset] = 'O'

Expand All @@ -1422,6 +1427,17 @@ def generate_idnits2_rfc_status():
# RFC200 is an old RFC List by Number
blob[200 -1] = 'O'

# !! Do not remove: idnits2 rejects this entire file if RFC16 is not 'O' !!
#
# This deliberately contradicts both the datatracker and the RFC Editor, which
# record RFC16 as updated rather than obsoleted. idnits2 validates its download
# of this file by matching the first 64 characters against a literal pattern that
# asserts 'O' here, inherited from a tools.ietf.org curation that disagreed with
# the RFC Editor. A mismatch makes idnits2 discard the file as corrupt and fall
# back to whatever stale copy it has, silently performing no RFC status checks at
# all. Removing this line therefore breaks every idnits2 client, not just RFC16.
blob[16 - 1] = 'O'

# End Workarounds

blob = re.sub('N*$','',''.join(blob))
Expand Down
Loading