{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "",
    "type": "object",
    "properties": {
      "salt": {
        "type": "string",
        "pattern": "^[0-9a-fA-F]{16}$",
        "description": "16-character hex salt applied to local password hashes."
      },
      "auth_mode": {
        "type": "string",
        "pattern": "^(oauth|local|both)$"
      },
      "oauth_provider": {
        "type": "string",
        "pattern": "^(google|github)?$"
      },
      "oauth_client_id": {
        "type": "string",
        "minLength": 0
      },
      "oauth_client_secret": {
        "type": "string",
        "minLength": 0
      },
      "oauth_redirect_uri": {
        "type": "string",
        "minLength": 0
      },
      "oauth_username_from": {
        "type": "string",
        "pattern": "^(sub|email|preffered_username|login|name)$"
      },
      "oauth_allowed_emails": {
        "type": "array",
        "description": "OAuth sign-in allowlist. Empty allows all. Entries support fnmatch globs (*, ?) on the normalized e-mail.",
        "items": {
          "type": "string",
          "minLength": 1
        }
      },
      "oauth_permissions": {
        "type": "object",
        "description": "Map of permission keys to principal emails (or local usernames). Key * grants all permissions.",
        "properties": {
          "*": {
            "type": "array",
            "items": { "type": "string" }
          },
          "pgw.addprojects": {
            "type": "array",
            "items": { "type": "string" }
          },
          "pgw.settings": {
            "type": "array",
            "items": { "type": "string" }
          }
        },
        "additionalProperties": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Scoped keys: pgw.read.{scope}, pgw.write.{scope}, pgw.write_branch.{project/branch}, pgw.boards.{scope}, pgw.tasks.{scope}, pgw.comments.{scope}, pgw.hooks.{scope}, pgw.mr.create.{scope}, pgw.mr.merge.{scope} (fnmatch). Principal * matches any authenticated user."
        }
      },
      "local_users": {
        "type": "array",
        "uniqueItems": true,
        "minItems": 1,
        "items": {
          "required": [
            "user"
          ],
          "oneOf": [
            { "required": ["pass_hash"] },
            { "required": ["pass"] }
          ],
          "properties": {
            "user": {
              "type": "string",
              "minLength": 2
            },
            "pass": {
              "type": "string",
              "minLength": 8,
              "description": "Plaintext password; hashed to pass_hash on first server start, then removed."
            },
            "pass_hash": {
              "type": "string",
              "minLength": 1,
              "description": "scrypt password hash (written by the server)."
            },
            "email": {
              "type": "string",
              "format": "email",
              "description": "Optional e-mail for Gravatar and permission grants by principal e-mail."
            },
            "assume_anonymous": {
              "type": "boolean",
              "description": "If true, unauthenticated requests assume this user for read permissions (e.g. public viewer role)."
            },
            "keys": {
              "type": "array",
              "description": "Smart HTTP credentials for this user. Git sends the local username or e-mail as the Basic username and the key as the password. Login passwords are not accepted.",
              "items": {
                "type": "object",
                "required": ["id", "secret", "time_issued"],
                "properties": {
                  "id": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Label unique among this user's keys."
                  },
                  "secret": {
                    "type": "string",
                    "minLength": 1,
                    "description": "scrypt hash of the key, same format as pass_hash. Plaintext is not accepted."
                  },
                  "readonly": {
                    "type": "boolean",
                    "description": "If true, the key can fetch (git-upload-pack) but not push (git-receive-pack)."
                  },
                  "time_issued": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the key was issued (ISO-8601)."
                  },
                  "time_expiry": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the key stops authenticating (ISO-8601). Omit for a key that does not expire. A key is expired at this instant."
                  }
                }
              }
            }
          }
        }
      }
    },
    "required": [
      "auth_mode",
      "salt"
    ]
  }