Skip to content

ABNF suggestions #858

Closed
1 of 1 issue completed
Closed

Description

@ahouseholder

(Comments from @tschmidtb51)

Given my thought process over time and during that review: I'm now full convinced that we should differentiate between language and x-name as this improves parsing and validation significantly. Therefore, I suggest - in addition with some other improvements:

  • all lower case except for BCP 47
  • allow for fragment parts also in unregistered namespaces
  • correct extentions in BCP 47
  • explicitly state reverse DNS (except for the length rule - that need to be in the regex)
!!! info "ABNF Notation"

    ```abnf
    namespace = base-ns [extensions]
    ; Overall namespace must be 3–1000 characters
    ; (Enforced via regex length lookahead)
    
    base-ns = x-base / std-base
    x-base  = "x_" x-name 
    std-base = ns-core
    
    ; ns-core starts with a lowercase letter and may have '.' or '-' separators.
    ; Consecutive '.' or '-' are not allowed.
    ns-core = LOWER ALNUMLOW *("." / "-" 1*ALNUMLOW)
    
    x-name = reverse-dns [ "#" fragment-seg ]
    
    ; reverse-dns provides an specification for a reverse DNS name
    ; can't be longer than 253 characters
    reverse-dns = label 1*("." label)
    
    ; Each label must be between 1 and 63 characters long
    label = ALNUMLOW [ *61(ALNUMLOWDASH)  ALNUMLOW ]
    
    fragment-seg = 1*ALNUMLOW *( ("." / "-") 1*ALNUMLOW )
    
    extensions = lang-ext [ 1*("/" ext-seg) ]
    
    ; Language extension: either / (empty language extension)
    ; or /<bcp47>/ (BCP-47 language code)
    lang-ext = "/" /  ( "/" bcp47 )
    
    ; Extension segment between slashes.
    ; - Must start with ALPHA
    ; - May have '.' or '-' separators
    ; - Optional '#' section, at most one per segment
    ; - No consecutive '.' or '-'
    ext-seg = bcp47 / "." x-name
    
    ; BCP-47 tag (based on the regex expansion)
    bcp47 = ( 2*3ALPHA
                [ "-" 3ALPHA *2( "-" 3ALPHA ) ]
            / 4*8ALPHA )
            [ "-" 4ALPHA ]
            [ "-" ( 2ALPHA / 3DIGIT ) ]
            * ( "-" ( 5*8ALNUM / DIGIT 3ALNUM ) )
            * ( "-"  singleton 1*("-" (2*83ALNUM)))
            [ "-" "x" 1*( "-" 1*8ALNUM ) ]
          / "x" 1*( "-" 1*8ALNUM )
          / "i-default"
          / "i-mingo"

                                     ; Single alphanumerics
                                     ; "x" reserved for private use
     singleton     = DIGIT               ; 0 - 9
                             / %x41-57             ; A - W
                             / %x59-5A             ; Y - Z
                             / %x61-77             ; a - w
                             / %x79-7A             ; y - z
    
    ; Character sets
    LOWER = %x61-7A   ; a-z
    ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
    DIGIT = %x30-39   ; 0-9
    ALNUM = ALPHA / DIGIT
    ALNUMLOW = LOWER / DIGIT
    SPECIALCHAR = DOT / DASH
    DOT = %x2E; .
    DASH = %x2D ; -
    ALNUMLOWSC = ALNUMLOW / SPECIALCHAR
    ALNUMLOWDASH = ALNUMLOW / DASH
    
    ; Constraints:
    ; - No consecutive "." or "-" in ns-core or ext-seg; exception in label
    ; - Each ext-seg can contain at most one "#".
    ; - Overall namespace is 3–1000 chars.
    ```

The question whether a-a-----a or a---a is valid as label is still open. Based on the RFC 1035, I would say yes. For the latter one, dig complains about some IDNA2008...

@ahouseholder @sei-vsarvepalli: I hope I corrected all mistakes I discovered earlier but please double check.

Originally posted by @tschmidtb51 in #821 (comment)

Activity

  1. tschmidtb51 commented on Aug 8, 2025

    @tschmidtb51
    Contributor

    Based on our discussion today:

    !!! info "ABNF Notation"
    
        ```abnf
        namespace = base-ns [extensions]
        ; Overall namespace must be 3–1000 characters
        ; (Enforced via regex length lookahead)
        
        base-ns = x-base / reg-base
        x-base  = "x_" x-name 
        reg-base = ns-core [ "#" fragment-seg ]
        
        ; ns-core starts with a lowercase letter and may have '.' or '-' separators.
        ; Consecutive '.' or '-' are not allowed.
        ; It needs at least 3 characters.
        ns-core = LOWER ALNUMLOW 1*( [ "." / "-" ] 1*ALNUMLOW)
        
        x-name = reverse-dns  "#" fragment-seg 
        
        ; reverse-dns provides an specification for a reverse DNS name
        ; can't be longer than 253 characters
        reverse-dns = label 1*("." label)
        
        ; Each label must be between 1 and 63 characters long
        label = ALNUMLOW [ *61(ALNUMLOWDASH)  ALNUMLOW ]
        
        fragment-seg = 1*ALNUMLOW *( ("." / "-") 1*ALNUMLOW )
        
        extensions = lang-ext [ 1*("/" ext-seg) ]
        
        ; Language extension: either / (empty language extension)
        ; or /<bcp47>/ (BCP-47 language code)
        lang-ext = "/" /  ( "/" bcp47 )
        
        ; Extension segment between slashes.
        ; - is either a language or
        ; - a model or
        ; - a third-party/unofficial translation
        ext-seg = bcp47 / "." x-name / translation 
        
        ; BCP-47 tag (based on the regex expansion)
        bcp47 = ( 2*3ALPHA
                    [ "-" 3ALPHA *2( "-" 3ALPHA ) ]
                / 4*8ALPHA )
                [ "-" 4ALPHA ]
                [ "-" ( 2ALPHA / 3DIGIT ) ]
                * ( "-" ( 5*8ALNUM / ( DIGIT 3ALNUM ) ) )
                * ( "-"  singleton 1*("-" (2*8ALNUM)))
                [ "-" "x" 1*( "-" 2*8ALNUM ) ]
              / "x" 1*( "-" 2*8ALNUM )
              / "i-default"
              / "i-mingo"
    
                                         ; Single alphanumerics
                                         ; "x" reserved for private use
         singleton     = DIGIT               ; 0 - 9
                                 / %x41-57             ; A - W
                                 / %x59-5A             ; Y - Z
                                 / %x61-77             ; a - w
                                 / %x79-7A             ; y - z
       
        ; Translations is either a
        ; - third-party/unofficial translation (depicted by using the reverse-dns before the target language) or
        ; - a (context) model (depicted by using the x-name) directly used in a different language 
        translation = "." ( reverse-dns /  x-name ) "$" bcp47
    
        ; Character sets
        LOWER = %x61-7A   ; a-z
        ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
        DIGIT = %x30-39   ; 0-9
        ALNUM = ALPHA / DIGIT
        ALNUMLOW = LOWER / DIGIT
        SPECIALCHAR = DOT / DASH
        DOT = %x2E; .
        DASH = %x2D ; -
        ALNUMLOWSC = ALNUMLOW / SPECIALCHAR
        ALNUMLOWDASH = ALNUMLOW / DASH
        
        ; Constraints:
        ; - No consecutive "." or "-" in ns-core or ext-seg; exception in label
        ; - Each ext-seg can contain at most one "#".
        ; - Overall namespace is 3–1000 chars.
        ```
    

    Notable changes:

    • registered namespaces (reg-base) are allow to have fragments
    • private namespaces (x-base) are required to have fragments
    • a registered namespace MUST be at least 3 characters long
    • in extensions, a fragment is required
    • a third-party or "unofficial" translation now shows the target language
    • a (context) model applied without a version in the previous language appends its language directly
    • official translations keep being ext-segs
  2. tschmidtb51 commented on Aug 8, 2025

    @tschmidtb51
    Contributor

    Valid Examples and their meaning

    Example Description
    ssvc//.de.bund.bsi$de-DE BSI's translation of SSVC
    ssvc//.de.bund.bsi#ref-arch-1/de-DE BSI's official translation to German as used in Germany of its ref-arch-1 model which is originally written in English
    ssvc//.de.bund.bsi#ref-arch-2$de-DE BSI's ref-arch-2 model which is originally written in German
    ssvc//.de.bund.bsi#ref-arch-2$de-DE/en-GB BSI's official translation to English as used in GB of its ref-arch-2 model which is originally written in German
    nist#800-30 NIST's registered model regarding its publication 800-30
    x_gov.nist#800-30/de-DE NIST's official translation to German as used in Germany of its model (regarding its publication) 800-30
    x_gov.nist#800-30//.de.bund.bsi$de-DE BSI's translation to German as used in Germany of NIST's model (regarding its publication) 800-30

    Invalid Examples

    Example Reasons
    ssvc$de-DE official translations / base language are at the first extension level
    anssi#800-30$fr-FR official translations / base language are at the first extension level
    x_gov.nist#800-30$de-DE official translations / base language are at the first extension level
    x_gov.nist#800-30/.de.bund.bsi$de-DE official translations / base language are at the first extension level
  3. tschmidtb51 commented on Aug 8, 2025

    @tschmidtb51
    Contributor

    @ahouseholder Small gap with ssvc$de-DE: How do we communicate, that a model is in a certain language only (aka its "base" language)? I think, we currently assume that all are in en-US. Do we actually care? (Currently, I would tend to say "No".)

  4. ahouseholder commented on Aug 8, 2025

    @ahouseholder
    ContributorAuthor

    I would expect foo/de-DE, foo#bar/de-DE or x_foo#bar/de-DE to be sufficient for this.
    My preference is to keep it simple and not add more complexity if we can avoid it though.

    But I could also see an argument for

    ns string fragment language
    foo optional, omitted optional, omitted => en-US
    foo$de-DE optional, omitted optional
    foo#bar$de-DE optional, included optional, included
    x_foo#bar$de-DE required, included optional, omitted=>en-US

    being reasonable if there's sufficient need for it. I'm leaning toward YAGNI on this one, but open to discussion.

  5. added
    enhancementNew feature or request
    integration/blockerSomething that is blocking integration with another framework or system
    tech/backendBack-end tools, code, infrastructure
    tech/dataData implementation (content of /data, data object instances, etc.)
    integrationRelated to integration of SSVC into another framework or system
    on Aug 8, 2025
  6. added this to the 2025-09 milestone on Aug 8, 2025
  7. tschmidtb51 commented on Aug 12, 2025

    @tschmidtb51
    Contributor

    My preference is to keep it simple and not add more complexity if we can avoid it though.

    Sounds good to me.

    I'm leaning toward YAGNI on this one, but open to discussion.

    Let's leave it as is and not allow base language as separate indicator for now.

  8. tschmidtb51 commented on Aug 12, 2025

    @tschmidtb51
    Contributor

    @ahouseholder We are good to start with the PR here, correct?

  9. 2 remaining items

  10. bernhardreiter commented on Aug 13, 2025

    @bernhardreiter
    Contributor

    (documenting first steps, will analyse it further)

    Gave #858 (comment) a spin with

    abnf              2.4.0
    abnf-to-regexp    1.1.3
    python 3.11.2
    

    after:

    • removing leading spaces
    • removing the leading and trailing lines, not part of the ABNF itself
    • converting line endings to CRLF
    • eliminating the second line with ; Overall namespace must be 3–1000 characters

    running abnf-to-regexp --format single-regexp -i s1.abnf complains about:

    Parsing error at line 43: ABNFGrammarRule('rulelist'): 1304:
    
    ') )\n        * ( "-"  singleton 1*("-" (2*83ALNUM)))\n        [ "-" "x" 1*( "-" 1*8ALNUM ) ]\n      / "x" 1*( "-" 1*8ALNUM )\n      / "i-default"\n      / "i-mingo"\n\n                                 ; Sing'
    
  11. bernhardreiter commented on Aug 14, 2025

    @bernhardreiter
    Contributor

    (progress to understand one error message):
    For abnf-to-regexp to work, the file must be 7-bit and the lines must be terminated by CRLF.

    od  -t x1 -v  s1.abnf | grep " [89a-f]"
    0000060 73 70 61 63 65 20 6d 75 73 74 20 62 65 20 33 e2
    0000100 80 93 31 30 30 30 20 63 68 61 72 61 63 74 65 72
    0005140 20 69 73 20 33 e2 80 93 31 30 30 30 20 63 68 61
    

    That is twice an unicode EN DASH character, encoded as UTF-8: 0xe2.80.93 in a comment.

  12. bernhardreiter commented on Aug 14, 2025

    @bernhardreiter
    Contributor

    Here is a version of the above ABNF file that can be parsed by abnf-to-regexp and the resulting output.

    (@tschmidtb51 has contracted me and my colleagues to assist with this issue. I will see for the next steps later.)

    Here is the diff, which removes the unicode characters, and three whitespaces which are not allowed:

    diff -U0 s1.abnf s2.abnf 
    --- s1.abnf     2025-08-14 08:59:25.143017562 +0200
    +++ s2.abnf     2025-08-14 09:30:49.371144168 +0200
    @@ -2 +2 @@
    -; Overall namespace must be 3–1000 characters
    +; Overall namespace must be 3-1000 characters
    @@ -43,2 +43,2 @@
    -        * ( "-" ( 5*8ALNUM / DIGIT 3ALNUM ) )
    -        * ( "-"  singleton 1*("-" (2*83ALNUM)))
    +        *( "-" ( 5*8ALNUM / DIGIT 3ALNUM ) )
    +        *( "-"  singleton 1*("-" (2*83ALNUM)))
    @@ -52 +52 @@
    - singleton     = DIGIT               ; 0 - 9
    +singleton     = DIGIT               ; 0 - 9
    @@ -78 +78 @@
    -; - Overall namespace is 3–1000 chars.
    +; - Overall namespace is 3-1000 chars.

    Working filename s2.abnf, to be saved with CRLF line terminations, though abnf-to-regexp also works on it with LF line terminations on GNU/Linux:

    namespace = base-ns [extensions]
    ; Overall namespace must be 3-1000 characters
    ; (Enforced via regex length lookahead)
    
    base-ns = x-base / reg-base
    x-base  = "x_" x-name 
    reg-base = ns-core [ "#" fragment-seg ]
    
    ; ns-core starts with a lowercase letter and may have '.' or '-' separators.
    ; Consecutive '.' or '-' are not allowed.
    ; It needs at least 3 characters.
    ns-core = LOWER ALNUMLOW 1*( [ "." / "-" ] 1*ALNUMLOW)
    
    x-name = reverse-dns  "#" fragment-seg 
    
    ; reverse-dns provides an specification for a reverse DNS name
    ; can't be longer than 253 characters
    reverse-dns = label 1*("." label)
    
    ; Each label must be between 1 and 63 characters long
    label = ALNUMLOW [ *61(ALNUMLOWDASH)  ALNUMLOW ]
    
    fragment-seg = 1*ALNUMLOW *( ("." / "-") 1*ALNUMLOW )
    
    extensions = lang-ext [ 1*("/" ext-seg) ]
    
    ; Language extension: either / (empty language extension)
    ; or /<bcp47>/ (BCP-47 language code)
    lang-ext = "/" /  ( "/" bcp47 )
    
    ; Extension segment between slashes.
    ; - is either a language or
    ; - a model or
    ; - a third-party/unofficial translation
    ext-seg = bcp47 / "." x-name / translation 
    
    ; BCP-47 tag (based on the regex expansion)
    bcp47 = ( 2*3ALPHA
                [ "-" 3ALPHA *2( "-" 3ALPHA ) ]
            / 4*8ALPHA )
            [ "-" 4ALPHA ]
            [ "-" ( 2ALPHA / 3DIGIT ) ]
            *( "-" ( 5*8ALNUM / DIGIT 3ALNUM ) )
            *( "-"  singleton 1*("-" (2*83ALNUM)))
            [ "-" "x" 1*( "-" 1*8ALNUM ) ]
          / "x" 1*( "-" 1*8ALNUM )
          / "i-default"
          / "i-mingo"
    
                                     ; Single alphanumerics
                                     ; "x" reserved for private use
    singleton     = DIGIT               ; 0 - 9
                             / %x41-57             ; A - W
                             / %x59-5A             ; Y - Z
                             / %x61-77             ; a - w
                             / %x79-7A             ; y - z
    
    ; Translations is either a
    ; - third-party/unofficial translation (depicted by using the reverse-dns before the target language) or
    ; - a (context) model (depicted by using the x-name) directly used in a different language 
    translation = "." ( reverse-dns /  x-name ) "$" bcp47
    
    ; Character sets
    LOWER = %x61-7A   ; a-z
    ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
    DIGIT = %x30-39   ; 0-9
    ALNUM = ALPHA / DIGIT
    ALNUMLOW = LOWER / DIGIT
    SPECIALCHAR = DOT / DASH
    DOT = %x2E; .
    DASH = %x2D ; -
    ALNUMLOWSC = ALNUMLOW / SPECIALCHAR
    ALNUMLOWDASH = ALNUMLOW / DASH
    
    ; Constraints:
    ; - No consecutive "." or "-" in ns-core or ext-seg; exception in label
    ; - Each ext-seg can contain at most one "#".
    ; - Overall namespace is 3-1000 chars.

    running abnf-to-regexp --format python-nested -i s2.abnf:

    alnum = '[a-zA-Z0-9]'
    lower = '[a-z]'
    alnumlow = f'({lower}|[0-9])'
    dash = '-'
    alnumlowdash = f'({alnumlow}|{dash})'
    dot = '\\.'
    specialchar = f'({dot}|{dash})'
    alnumlowsc = f'({alnumlow}|{specialchar})'
    label = f'{alnumlow}(({alnumlowdash}){{,61}}{alnumlow})?'
    reverse_dns = f'{label}(\\.{label})+'
    fragment_seg = f'({alnumlow})+([.\\-]({alnumlow})+)*'
    x_name = f'{reverse_dns}\\#{fragment_seg}'
    x_base = f'x_{x_name}'
    ns_core = f'{lower}{alnumlow}([.\\-]?({alnumlow})+)+'
    reg_base = f'{ns_core}(\\#{fragment_seg})?'
    base_ns = f'({x_base}|{reg_base})'
    singleton = '[0-9A-WY-Za-wy-z]'
    bcp47 = (
        '(([a-zA-Z]{2,3}(-[a-zA-Z]{3}(-[a-zA-Z]{3}){,2})?|[a-z'
        'A-Z]{4,8})(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-'
        f'(({alnum}){{5,8}}|[0-9]({alnum}){{3}}))*(-{singleton}(-'
        f'({alnum}){{2,83}})+)*(-[xX](-({alnum}){{1,8}})+)?|[xX](-'
        f'({alnum}){{1,8}})+|i-default|i-mingo)'
    )
    translation = f'\\.({reverse_dns}|{x_name})\\${bcp47}'
    ext_seg = f'({bcp47}|\\.{x_name}|{translation})'
    lang_ext = f'(/|/{bcp47})'
    extensions = f'{lang_ext}((/{ext_seg})+)?'
    namespace = f'{base_ns}({extensions})?'

    running abnf-to-regexp --format single-regexp -i s2.abnf:

    (x_[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?){1,}\#[a-z0-9]{1,}([.\-][a-z0-9]{1,})*|[a-z][a-z0-9]([.\-]?[a-z0-9]{1,}){1,}(\#[a-z0-9]{1,}([.\-][a-z0-9]{1,})*)?)((/|/(([a-zA-Z]{2,3}(\-[a-zA-Z]{3,3}(\-[a-zA-Z]{3,3}){0,2})?|[a-zA-Z]{4,8})(\-[a-zA-Z]{4,4})?(\-([a-zA-Z]{2,2}|[0-9]{3,3}))?(\-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3,3}))*(\-[0-9A-WY-Za-wy-z](\-[a-zA-Z0-9]{2,83}){1,})*(\-[xX](\-[a-zA-Z0-9]{1,8}){1,})?|[xX](\-[a-zA-Z0-9]{1,8}){1,}|i\-default|i\-mingo))((/((([a-zA-Z]{2,3}(\-[a-zA-Z]{3,3}(\-[a-zA-Z]{3,3}){0,2})?|[a-zA-Z]{4,8})(\-[a-zA-Z]{4,4})?(\-([a-zA-Z]{2,2}|[0-9]{3,3}))?(\-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3,3}))*(\-[0-9A-WY-Za-wy-z](\-[a-zA-Z0-9]{2,83}){1,})*(\-[xX](\-[a-zA-Z0-9]{1,8}){1,})?|[xX](\-[a-zA-Z0-9]{1,8}){1,}|i\-default|i\-mingo)|\.[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?){1,}\#[a-z0-9]{1,}([.\-][a-z0-9]{1,})*|\.([a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?){1,}|[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?){1,}\#[a-z0-9]{1,}([.\-][a-z0-9]{1,})*)\$(([a-zA-Z]{2,3}(\-[a-zA-Z]{3,3}(\-[a-zA-Z]{3,3}){0,2})?|[a-zA-Z]{4,8})(\-[a-zA-Z]{4,4})?(\-([a-zA-Z]{2,2}|[0-9]{3,3}))?(\-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3,3}))*(\-[0-9A-WY-Za-wy-z](\-[a-zA-Z0-9]{2,83}){1,})*(\-[xX](\-[a-zA-Z0-9]{1,8}){1,})?|[xX](\-[a-zA-Z0-9]{1,8}){1,}|i\-default|i\-mingo))){1,})?)?
  13. tschmidtb51 commented on Aug 14, 2025

    @tschmidtb51
    Contributor

    @bernhardreiter Just saw that there is a mistake in the original file: 83ALNUM must be 8ALNUM according to BCP47

  14. tschmidtb51 commented on Aug 14, 2025

    @tschmidtb51
    Contributor

    @bernhardreiter Updated your raw version:

    namespace = base-ns [extensions]
    ; Overall namespace must be 3-1000 characters
    ; (Enforced via regex length lookahead)
    
    base-ns = x-base / reg-base
    x-base  = "x_" x-name 
    reg-base = ns-core [ "#" fragment-seg ]
    
    ; ns-core starts with a lowercase letter and may have '.' or '-' separators.
    ; Consecutive '.' or '-' are not allowed.
    ; It needs at least 3 characters.
    ns-core = LOWER ALNUMLOW 1*( [ "." / "-" ] 1*ALNUMLOW)
    
    x-name = reverse-dns  "#" fragment-seg 
    
    ; reverse-dns provides an specification for a reverse DNS name
    ; can't be longer than 253 characters
    reverse-dns = label 1*("." label)
    
    ; Each label must be between 1 and 63 characters long
    label = ALNUMLOW [ *61(ALNUMLOWDASH)  ALNUMLOW ]
    
    fragment-seg = 1*ALNUMLOW *( ("." / "-") 1*ALNUMLOW )
    
    extensions = lang-ext [ 1*("/" ext-seg) ]
    
    ; Language extension: either / (empty language extension)
    ; or /<bcp47>/ (BCP-47 language code)
    lang-ext = "/" /  ( "/" bcp47 )
    
    ; Extension segment between slashes.
    ; - is either a language or
    ; - a model or
    ; - a third-party/unofficial translation
    ext-seg = bcp47 / "." x-name / translation 
    
    ; BCP-47 tag (based on the regex expansion)
    bcp47 = ( 2*3ALPHA
                [ "-" 3ALPHA *2( "-" 3ALPHA ) ]
            / 4*8ALPHA )
            [ "-" 4ALPHA ]
            [ "-" ( 2ALPHA / 3DIGIT ) ]
            *( "-" ( 5*8ALNUM / (DIGIT 3ALNUM) ) )
            *( "-"  singleton 1*("-" (2*8ALNUM)))
            [ "-" "x" 1*( "-" 2*8ALNUM ) ]
          / "x" 1*( "-" 2*8ALNUM )
          / "i-default"
          / "i-mingo"
    
                                     ; Single alphanumerics
                                     ; "x" reserved for private use
    singleton     = DIGIT               ; 0 - 9
                             / %x41-57             ; A - W
                             / %x59-5A             ; Y - Z
                             / %x61-77             ; a - w
                             / %x79-7A             ; y - z
    
    ; Translations is either a
    ; - third-party/unofficial translation (depicted by using the reverse-dns before the target language) or
    ; - a (context) model (depicted by using the x-name) directly used in a different language 
    translation = "." ( reverse-dns /  x-name ) "$" bcp47
    
    ; Character sets
    LOWER = %x61-7A   ; a-z
    ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
    DIGIT = %x30-39   ; 0-9
    ALNUM = ALPHA / DIGIT
    ALNUMLOW = LOWER / DIGIT
    SPECIALCHAR = DOT / DASH
    DOT = %x2E; .
    DASH = %x2D ; -
    ALNUMLOWSC = ALNUMLOW / SPECIALCHAR
    ALNUMLOWDASH = ALNUMLOW / DASH
    
    ; Constraints:
    ; - No consecutive "." or "-" in ns-core or ext-seg; exception in label
    ; - Each ext-seg can contain at most one "#".
    ; - Overall namespace is 3-1000 chars.
  15. bernhardreiter commented on Aug 15, 2025

    @bernhardreiter
    Contributor

    based on a branch with fixed testing framework (having applied #881), https://github.com/Intevation/certcc-SSVC/commit/574f4c8bd878a798156deeb1cfd66456dc351009 adds the pattern from above to the testsuite as preparation to resolve this issue.

    So a failed test is expected, here is the message:

    pytest -vvv src/test/test_namespaces_pattern.py
    [..]
    FAILED src/test/test_namespaces_pattern.py::
    TestNamespacePattern::test_ns_pattern - AssertionError:
    ['Should match ssvc//.de.bund.bsi$de-DE', 
     'Should match ssvc//.de.bund.bsi#ref-arch-1/de-DE',
     'Should match ssvc//.de.bund.bsi#ref-arch-2$de-DE',
     'Should match ssvc//.de.bund.bsi#ref-arch-2$de-DE/en-GB',
     'Should match nist#800-30',
     'Should match x_gov.nist#800-30/de-DE',
     'Should match x_gov.nist#800-30/.de.bund.bsi$de-DE']
    is not false
    

    (some line endings added for readability)

  16. bernhardreiter commented on Aug 15, 2025

    @bernhardreiter
    Contributor

    The latest ABNF here (working name s3.abnf) from above mandates a # for x_base type namespaces:

    x-name = reverse-dns  "#" fragment-seg 

    this leads to x_com.yahooinc being invalid and number of testcases have to be changed.

    It is intentional as #858 (comment) has:

    Notable changes:

    • private namespaces (x-base) are required to have fragments
  17. tschmidtb51 commented on Aug 15, 2025

    @tschmidtb51
    Contributor

    this leads to x_com.yahooinc being invalid and number of testcases have to be changed.

    Yes. As we changed the structure (based on the decisions conveyed by the ABNF) some test cases will be invalid and need to be adapted.

  18. bernhardreiter commented on Aug 15, 2025

    @bernhardreiter
    Contributor

    One of the valid examples from above (#858 (comment)) is

    x_gov.nist#800-30/.de.bund.bsi$de-DE

    but this does not validate from the ABNF, because a single / is the empty lang-ext then only a second slash can follow before a translation.

    @tschmidtb51 Am I correct and the example should be corrected to x_gov.nist#800-30//.de.bund.bsi$de-DE (with the slash added)?

    (I'll continue working with that assumption.)

  19. bernhardreiter commented on Aug 15, 2025

    @bernhardreiter
    Contributor

    In addition to changes here, the documentation in https://github.com/CERTCC/SSVC/blob/main/docs/reference/code/namespaces.md will need further updates. I will replace x_example.test with x_org.example#bar, but it is not entirely clear to me how the surrounding text should be updated with the changes that come with this issue.

  20. bernhardreiter commented on Aug 15, 2025

    @bernhardreiter
    Contributor

    New merge requests #882 will resolve the issue, see detailed remarks there.

  21. tschmidtb51 commented on Aug 15, 2025

    @tschmidtb51
    Contributor

    One of the valid examples from above (#858 (comment)) is

    x_gov.nist#800-30/.de.bund.bsi$de-DE

    but this does not validate from the ABNF, because a single / is the empty lang-ext then only a second slash can follow before a translation.

    @tschmidtb51 Am I correct and the example should be corrected to x_gov.nist#800-30//.de.bund.bsi$de-DE (with the slash added)?

    (I'll continue working with that assumption.)

    Yes. I updated that above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or requestintegrationRelated to integration of SSVC into another framework or systemintegration/blockerSomething that is blocking integration with another framework or systemtech/backendBack-end tools, code, infrastructuretech/dataData implementation (content of /data, data object instances, etc.)

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions