inbox must be an OrderedCollection

Description

This rule checks whether the inbox property of an object appears to be an OrderedCollection

Table of Contents

Identifiers

Use these identifiers to refer to this Test.

URI

urn:uuid:5e94d155-ed4a-4d71-b797-d7c387736ecf

slug

This slug is memorable, but it is not guaranteed to be globally unique like a URI.

inbox-must-be-an-orderedcollection

Input

This describes the input that each test run will use to select test targets.

input.object

the object whose `inbox` property will be tested

required
true
range
https://www.w3.org/ns/activitystreams#Actor

input.object as json
{
  "help": "the object whose `inbox` property will be tested",
  "required": true,
  "rangeIncludes": [
    "https://www.w3.org/ns/activitystreams#Actor"
  ]
}

input.time

amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.

required
true
type
rfc3339:dur-time, TimeLimit
constraints
[
  {
    "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
    "mediaType": "test/markdown"
  }
]

input.time as json
{
  "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
  "required": true,
  "default": "T5S",
  "type": [
    "rfc3339:dur-time",
    "TimeLimit"
  ],
  "constraints": [
    {
      "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
      "mediaType": "test/markdown"
    }
  ]
}

Input as JSON
{
  "object": {
    "help": "the object whose `inbox` property will be tested",
    "required": true,
    "rangeIncludes": [
      "https://www.w3.org/ns/activitystreams#Actor"
    ]
  },
  "time": {
    "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
    "required": true,
    "default": "T5S",
    "type": [
      "rfc3339:dur-time",
      "TimeLimit"
    ],
    "constraints": [
      {
        "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
        "mediaType": "test/markdown"
      }
    ]
  }
}

Requirement Mapping

This Test has been derived from these specified requirements.

  • urn:uuid:4edf6768-c751-448f-96ac-4ef44cb4291f

    content
    The inbox MUST be an OrderedCollection.
    origin
    {
      "source": "https://www.w3.org/TR/activitypub/",
      "section": {
        "id": "https://www.w3.org/TR/activitypub/#inbox",
        "branch": [
          5,
          2
        ]
      },
      "selector": {
        "type": "TextQuoteSelector",
        "exact": "The inbox MUST be an OrderedCollection.\n",
        "prefix": "The inbox is discovered through the inbox property of an actor's profile.\n",
        "suffix": "The inbox stream contains all activities received by the actor.\n"
      }
    }
    JSON
    {
      "id": "urn:uuid:4edf6768-c751-448f-96ac-4ef44cb4291f",
      "type": "Behavior",
      "uuid": "4edf6768-c751-448f-96ac-4ef44cb4291f",
      "content": "The inbox MUST be an OrderedCollection.",
      "tag": [
        {
          "name": "ActivityPubServer",
          "id": "https://socialweb.coop/tag/ActivityPubServer"
        }
      ],
      "origin": {
        "source": "https://www.w3.org/TR/activitypub/",
        "section": {
          "id": "https://www.w3.org/TR/activitypub/#inbox",
          "branch": [
            5,
            2
          ]
        },
        "selector": {
          "type": "TextQuoteSelector",
          "exact": "The inbox MUST be an OrderedCollection.\n",
          "prefix": "The inbox is discovered through the inbox property of an actor's profile.\n",
          "suffix": "The inbox stream contains all activities received by the actor.\n"
        }
      },
      "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://socialweb.coop/ns/testing/context.json"
      ]
    }

Part of

This test is part of the following Test Suites:

JSON

Test Case as JSON
{
  "description": "This rule checks whether the inbox property of an object appears to be an OrderedCollection",
  "failedCases": [
    {
      "name": "test case when the value of the inbox property is null",
      "input": {
        "object": "{\"inbox\":null}"
      },
      "result": {
        "outcome": "failed"
      }
    },
    {
      "name": "test case when inbox is an object without type OrderedCollection",
      "input": {
        "object": "{\"inbox\":{\"type\":[\"Person\"]}}"
      },
      "result": {
        "outcome": "failed"
      }
    },
    {
      "name": "inputs.object has inbox url to a non-collection",
      "input": {
        "authorization": "foo",
        "object": "{\"inbox\":\"https://bengo.is/actor.json\"}"
      },
      "result": {
        "outcome": "failed"
      }
    }
  ],
  "inapplicableCases": [
    {
      "name": "test case when the inbox property is missing",
      "input": {
        "object": "{}"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where the value of inputs.object is not JSON",
      "input": {
        "object": "\u0000x123abc_intentionallyNotJson"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where the value of of the inbox property is an array of length 2",
      "input": {
        "authorization": "",
        "object": "{\"inbox\":[\"https://example.com\",\"https://example.com\"]}"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where inbox property value is a URL that 404s when fetched",
      "input": {
        "object": {
          "inbox": "https://mastodon.social/users/bengo/inbox"
        }
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "inputs.object is null",
      "input": {
        "object": "null"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "inputs.object is a number",
      "input": {
        "object": "123"
      },
      "result": {
        "outcome": "inapplicable"
      }
    }
  ],
  "input": {
    "object": {
      "help": "the object whose `inbox` property will be tested",
      "required": true,
      "rangeIncludes": [
        "https://www.w3.org/ns/activitystreams#Actor"
      ]
    },
    "time": {
      "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
      "required": true,
      "default": "T5S",
      "type": [
        "rfc3339:dur-time",
        "TimeLimit"
      ],
      "constraints": [
        {
          "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
          "mediaType": "test/markdown"
        }
      ]
    }
  },
  "markdown": "---\ntype:\n- TestCase\nstatus: draft\nname: inbox must be an OrderedCollection\ndescription: |\n  This rule checks whether the inbox property of an object appears to be an OrderedCollection\nuuid: 5e94d155-ed4a-4d71-b797-d7c387736ecf\nattributedTo:\n- https://bengo.is\n\"@context\":\n- TestCase:\n    \"@id\": http://www.w3.org/ns/earl#:TestCase\n\nrespec:\n  config:\n    editors:\n    - name: bengo\n      url: \"https://bengo.is\"\n      w3cid: 49026\n---\n\n# inbox must be an OrderedCollection\n\n## Background\n\n[ActivityPub](https://www.w3.org/TR/activitypub/) [ยง 5.2 Inbox](https://www.w3.org/TR/activitypub/#inbox):\n> The inbox is discovered through the inbox property of an actor's profile. The inbox MUST be an OrderedCollection.\n\n## About this Test\n\nThis is a Test Case describing a rule to determine whether an ActivityPub object has an inbox property that meets this requirement to 'be an OrderedCollection', meeting requirement [4edf6768-c751-448f-96ac-4ef44cb4291f](https://socialweb.coop/activitypub/behaviors/4edf6768-c751-448f-96ac-4ef44cb4291f)\n\n### Identifier\n\nThe identifier of this test is `urn:uuid:5e94d155-ed4a-4d71-b797-d7c387736ecf`.\n\n## Test Subject\n\nThe subject of this test is any data claiming to conform to the specification of an ActivityPub Actor Object.\n\nThis test is *not* inherently applicable to an ActivityPub Server. An ActivityPub Server serves 0 or more Actor Objects. An ActivityPub Server for a big community might serve hundreds of ActivityPub Actor Objects. An ActivityPub Server for a single human may serve only that person's ActivityPub Actor Object.\n\nThis test is *not* inherently applicable to a URL of an Actor Object. The URL is not the same as the Actor Object. The URL may resolve to different Actor Objects in different contexts.\n\n## Inputs\n\nThis test requires the following [inputs](https://www.w3.org/TR/act-rules-format/#input):\n\n1. `object` - the object whose `inbox` property will be tested\n\n    * type: binary\n    * constraints\n        * will be interpreted as JSON\n\n2. `time` - amount of time allowed to run test. This is meant to configure the limit for how long this test will wait for network requests.\n\n    * required: yes\n    * example: `T0.0021S`\n    * type: bytes\n    * constraints\n        * MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)\n\n## Applicability\n\nThis test applies to inbox objects linked to from the `object` input. Usually an actor will have one inbox, but there may be multiple.\n\nThis test does not apply to objects with more than one inbox . If the input `object` has an inbox property whose value is an array of length >= 2, outcome is `inapplicable`.\n(See issue #5102 below to track expanding the applicability)\n\nIf `object` is not parseable as JSON to a JSON object, outcome is `inapplicable`.\n\nIf `object` is a JSON object, but it does not contain a property named `inbox`, outcome is `inapplicable`. The rationale is that there is already a test `acaacb5f-8f7e-4f28-8d81-c7955070a767` that can be used to determine if input `object` has an inbox property at all.\n\n### Test Targets\n\n1. `inbox` - the value of the `inbox` property in the input `object` object\n    * since the `object` object must be JSON for this test's applicability, the value of `JSON.parse(actor).inbox` must also be JSON\n    * how to derive `inbox` from inputs\n        1. let `inboxValue` be\n            * if `inputs.actor.inbox` is a JSON string, `inboxValue` is that string\n            * if `inputs.actor.inbox` is a JSON object, `inboxValue` is that object\n            * if `inputs.actor.inbox` is an Array of length 1, `inboxValue` is the item in that array\n            * if `inputs.actor.inbox` is an Array of length greater than 1, the test outcome is `not applicable` (covered in 'Applicability' above)\n              * see issue #5102 below to track expanding the applicability to support inbox property values that are arrays with length greater than 1\n        2. let `inboxObject` be\n            * if `inboxValue` is a json object, `inboxObject` is that object\n            * if `inboxValue` is a json string, `inboxObject` is the result of interpreting that string as an ActivityPub Object Identifier and fetching the corresponding ActivityPub Object (e.g. `GET https://...`).\n        3. test target `inbox` is `inboxValue`\n\n## Expectations\n\n1. `inbox` is a json object\n2. `inbox` has a property named `type`\n3. the values of the inbox's `type` property must contain `\"OrderedCollection\"`, as determined by\n    * if value of `inbox`'s `type` property is a string, it MUST be `\"OrderedCollection\"`\n    * if value of `inbox`'s `type` property is an Array, it MUST contain an entry identical to `\"OrderedCollection\"`\n\n## Assumptions\n\n### Interpreting \"MUST be an OrderedCollection\"\n\nRevisiting the background from above,\n[ActivityPub](https://www.w3.org/TR/activitypub/) [says](https://www.w3.org/TR/activitypub/#inbox)\n> The inbox is discovered through the inbox property of an actor's profile. The inbox MUST be an OrderedCollection.\n\n\"MUST be an OrderedCollection\" is open to some interpretation here.\n\nThis test chose to interpret 'be an' to include 'indicate its type as'. The rationale is that it's easy to check and easy to implement.\n\n## Test Cases\n\n### simple valid inbox\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"inbox\": {\n        \"id\": \"http://example.org/blog/\",\n        \"type\": \"OrderedCollection\",\n        \"name\": \"Martin's Blog\"\n      }\n    }\n    ```\n\n    * note: this OrderedCollection is from [Example 5 in activitystreams-core](https://www.w3.org/TR/activitystreams-core/#ex2-jsonld)\n\ntest targets\n\n* `inbox`\n    * value:\n\n        ```json\n        {\n        \"id\": \"http://example.org/blog/\",\n        \"type\": \"OrderedCollection\",\n        \"name\": \"Martin's Blog\"\n        }\n        ```\n\n    * outcome: `passed`\n\n### inbox is null\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"inbox\": null\n    }\n    ```\n\ntest targets\n\n* `inbox`\n    * value:\n\n        ```json\n        null\n        ```\n\n    * outcome: `failed`\n        * rationale: inbox is not an OrderedCollection\n\n### inbox type array contains only Person\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"inbox\": {\n        \"type\": [\"Person\"]\n      }\n    }\n    ```\n\ntest targets\n\n* `inbox`\n    * value:\n\n        ```json\n        {\n          \"type\": [\"Person\"]\n        }\n        ```\n\n    * outcome: `failed`\n        * rationale: inbox type is not OrderedCollection\n\n### object with no properties\n\ninputs\n\n* `object`\n\n    ```json\n    {}\n    ```\n\nresult\n\n* outcome: `inapplicable`\n\n### object is not JSON\n\ninputs\n\n* `object`\n\n    ```text\n    \\0x123abc_intentionallyNotJson\n    ```\n\nresult\n\n* outcome: `inapplicable`\n\n### inapplicable because inbox has many values\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"inbox\": [\"https://example.com\", \"https://example.com\"]\n    }\n    ```\n\ntest targets\n\n* `inbox`\n    * value:\n\n        ```json\n        [\"https://example.com\", \"https://example.com\"]\n        ```\n\n    * outcome: `inapplicable`\n        * rationale: inbox values that are arrays of length greater than 1 or inapplicable. See issue #5102 below to track expanding the applicability\n\n## Glossary\n\n### `outcome`\n\nAn outcome is a conclusion that comes from evaluating a test on a test subject. An outcome can be one of the three following types:\n\n* `inapplicable`: No part of the test subject matches the applicability\n* `passed`: A test target meets all expectations\n* `failed`: A test target does not meet all expectations\n\n## Requirements Mapping\n\n* [ActivityPub Requirement 4edf6768-c751-448f-96ac-4ef44cb4291f](https://socialweb.coop/activitypub/behaviors/4edf6768-c751-448f-96ac-4ef44cb4291f) - The inbox MUST be an OrderedCollection\n    * Required for Conformance to [ActivityPub][activitypub]\n    * Outcome Mapping\n        * when test target `inbox` has outcome `passed`, requirement is satisfied\n        * when test target `inbox` has outcome `failed`, requirement is not satisfied\n        * when test target `inbox` has outcome `inapplicable`, further testing is needed to determine requirement satisfaction\n\n## Change Log\n\n* 2023-11-15T01:18:34.191Z - first draft\n* 2023-11-16T06:09:56.915Z - finish all sections in first draft\n    * add test cases for passed outcome\n    * add test cases for failed outcome\n    * add test cases for inapplicable outcome\n    * add requirements mapping for <https://socialweb.coop/activitypub/requirements/4edf6768-c751-448f-96ac-4ef44cb4291f/>\n    * add a test case where inbox is a URI that is resolved to an OrderedCollection an the outcome is \"passed\"\n* 2023-12-29T21:51:17.983Z - reformat test cases\n\n## Issues\n\n* #01d2: resolving inbox url should use inputs.time and timeout\n* #5102: expand applicability to handle cases where there are multiple inboxes\n\n[activitypub]: https://www.w3.org/TR/activitypub/\n",
  "name": "inbox must be an OrderedCollection",
  "passedCases": [
    {
      "name": "test case when inbox is an OrderedCollection",
      "input": {
        "object": "{\"inbox\":{\"id\":\"http://example.org/blog/\",\"type\":\"OrderedCollection\",\"name\":\"Martin's Blog\"}}"
      },
      "result": {
        "outcome": "passed"
      }
    }
  ],
  "slug": "inbox-must-be-an-orderedcollection",
  "uuid": "5e94d155-ed4a-4d71-b797-d7c387736ecf",
  "isPartOf": [
    "https://socialweb.coop/activitypub/test-cases/"
  ],
  "requirementReference": [
    {
      "url": "https://socialweb.coop/activitypub/behaviors/4edf6768-c751-448f-96ac-4ef44cb4291f/",
      "id": "urn:uuid:4edf6768-c751-448f-96ac-4ef44cb4291f"
    }
  ]
}