{"id":38803714,"url":"https://github.com/paulbailey/mstr-rest-requests","last_synced_at":"2026-03-04T09:00:32.443Z","repository":{"id":57443749,"uuid":"173775645","full_name":"paulbailey/mstr-rest-requests","owner":"paulbailey","description":"A library for Python 3.9+ for interacting with MicroStrategy's REST API","archived":false,"fork":false,"pushed_at":"2026-02-25T01:26:15.000Z","size":519,"stargazers_count":2,"open_issues_count":4,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-02-25T06:59:24.437Z","etag":null,"topics":["microstrategy","mstr","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulbailey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-03-04T15:56:52.000Z","updated_at":"2025-12-17T15:09:09.000Z","dependencies_parsed_at":"2024-12-20T16:33:28.257Z","dependency_job_id":"e9f9c329-65b1-4617-90d2-477ac0a40344","html_url":"https://github.com/paulbailey/mstr-rest-requests","commit_stats":{"total_commits":149,"total_committers":6,"mean_commits":"24.833333333333332","dds":0.2953020134228188,"last_synced_commit":"2a5c023fd0b67af5ba3d2a17fc74add3aaa9bbe9"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/paulbailey/mstr-rest-requests","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulbailey%2Fmstr-rest-requests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulbailey%2Fmstr-rest-requests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulbailey%2Fmstr-rest-requests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulbailey%2Fmstr-rest-requests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulbailey","download_url":"https://codeload.github.com/paulbailey/mstr-rest-requests/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulbailey%2Fmstr-rest-requests/sbom","scorecard":{"id":683054,"data":{"date":"2025-08-11","repo":{"name":"github.com/paulbailey/mstr-rest-requests","commit":"49917660eb1fe8df39e3346041693f6b5487ddc6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/12 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":10,"reason":"23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/pythonpackage.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpackage.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/pythonpackage.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pythonpackage.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/pythonpackage.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pythonpackage.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/pythonpackage.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/pythonpublish.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/paulbailey/mstr-rest-requests/pythonpublish.yml/main?enable=pin","Warn: npmCommand not pinned by hash: scripts/deploy_serverless.sh:3","Warn: pipCommand not pinned by hash: scripts/deploy_serverless.sh:5","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":8,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 8 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T23:49:07.973Z","repository_id":57443749,"created_at":"2025-08-21T23:49:07.974Z","updated_at":"2025-08-21T23:49:07.974Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30076935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T08:01:56.766Z","status":"ssl_error","status_checked_at":"2026-03-04T08:00:42.919Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microstrategy","mstr","python"],"created_at":"2026-01-17T12:48:47.510Z","updated_at":"2026-03-04T09:00:32.408Z","avatar_url":"https://github.com/paulbailey.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mstr-rest-requests\n\nAn extension to the excellent [requests](https://docs.python-requests.org/) `Session` object, providing a more straightforward interface for the [MicroStrategy REST API](https://demo.microstrategy.com/MicroStrategyLibrary/api-docs/).\n\n![Python package](https://github.com/paulbailey/mstr-rest-requests/workflows/Python%20package/badge.svg)\n\n## Installation\n\n```bash\npip install mstr-rest-requests\n```\n\n### Extras\n\nTo use the built-in credential providers, install the corresponding extra:\n\n```bash\npip install mstr-rest-requests[aws]    # AWS Secrets Manager \u0026 SSM Parameter Store\npip install mstr-rest-requests[azure]  # Azure Key Vault\npip install mstr-rest-requests[gcp]    # Google Cloud Secret Manager\n```\n\n## Quick start\n\n```python\nfrom mstr.requests import AuthenticatedMSTRRESTSession\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\",\n    username=\"dave\",\n    password=\"hellodave\",\n) as session:\n    projects = session.get(\"projects\").json()\n```\n\nThe session automatically logs in when the context manager is entered and logs\nout when it exits.\n\n## Authentication\n\nFour authentication modes are supported. In every case you can use either the\ncontext-manager style shown above or the manual approach shown below.\n\n### Standard (username and password)\n\n```python\nfrom mstr.requests import MSTRRESTSession\n\nsession = MSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\"\n)\nsession.login(username=\"dave\", password=\"hellodave\")\n```\n\n### Identity token (delegation)\n\n```python\nsession.delegate(identity_token=\"supersecretidentitytoken\")\n```\n\n### API key (trusted authentication)\n\n```python\nsession.login(username=\"supersecretapikey\")\n```\n\n### Anonymous\n\n```python\nsession.login()\n```\n\n## Credential providers\n\nEvery credential parameter on `AuthenticatedMSTRRESTSession` -- including\n`base_url` -- accepts either a plain string **or** a zero-argument callable\nthat returns a string.  Callables are resolved lazily when the context manager\nis entered, not when the session is constructed.\n\nThis makes it easy to pull credentials from vaults, environment helpers, or any\nother source at connect time:\n\n```python\nfrom mstr.requests import AuthenticatedMSTRRESTSession\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\",\n    username=lambda: get_username_from_somewhere(),\n    password=lambda: get_password_from_somewhere(),\n) as session:\n    ...\n```\n\n### AWS Secrets Manager\n\nInstall with `pip install mstr-rest-requests[aws]`.\n\n#### Single-value secrets\n\nUse `secrets_manager` to create a callable for a single secret value:\n\n```python\nfrom mstr.requests import AuthenticatedMSTRRESTSession\nfrom mstr.requests.credentials.aws import secrets_manager\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\",\n    username=secrets_manager(\"my-secret-id\", key=\"username\"),\n    password=secrets_manager(\"my-secret-id\", key=\"password\"),\n) as session:\n    ...\n```\n\n#### Multi-field secrets\n\nWhen a single secret contains all connection details as a JSON object, use\n`SecretsManagerSecret` to fetch the secret once and share it across fields:\n\n```python\nfrom mstr.requests import AuthenticatedMSTRRESTSession\nfrom mstr.requests.credentials.aws import SecretsManagerSecret\n\nsecret = SecretsManagerSecret(\"my-secret-id\")\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=secret.field(\"base_url\"),\n    username=secret.field(\"username\"),\n    password=secret.field(\"password\"),\n) as session:\n    ...\n```\n\nThe secret is only fetched on the first field resolution, and the result is\ncached for all subsequent fields.\n\n### AWS SSM Parameter Store\n\nAlso covered by the `aws` extra (`pip install mstr-rest-requests[aws]`).\n\n#### Individual parameters\n\n```python\nfrom mstr.requests.credentials.aws import parameter_store\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=parameter_store(\"/myapp/mstr/base_url\"),\n    username=parameter_store(\"/myapp/mstr/username\"),\n    password=parameter_store(\"/myapp/mstr/password\"),\n) as session:\n    ...\n```\n\n#### Grouped parameters with caching\n\n`ParameterStoreValues` caches each parameter after the first fetch so\nrepeated resolutions of the same name do not make extra API calls:\n\n```python\nfrom mstr.requests.credentials.aws import ParameterStoreValues\n\nparams = ParameterStoreValues()\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=params.parameter(\"/myapp/mstr/base_url\"),\n    username=params.parameter(\"/myapp/mstr/username\"),\n    password=params.parameter(\"/myapp/mstr/password\"),\n) as session:\n    ...\n```\n\n### Azure Key Vault\n\nInstall with `pip install mstr-rest-requests[azure]`.  Authentication uses\n[`DefaultAzureCredential`](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential)\nwhich supports managed identity, environment variables, Azure CLI, and more.\n\n#### Single-value secrets\n\n```python\nfrom mstr.requests.credentials.azure import key_vault\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\",\n    username=key_vault(\"https://my-vault.vault.azure.net/\", \"mstr-username\"),\n    password=key_vault(\"https://my-vault.vault.azure.net/\", \"mstr-password\"),\n) as session:\n    ...\n```\n\n#### Multi-field secrets\n\n```python\nfrom mstr.requests.credentials.azure import KeyVaultSecret\n\nsecret = KeyVaultSecret(\"https://my-vault.vault.azure.net/\", \"mstr-connection\")\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=secret.field(\"base_url\"),\n    username=secret.field(\"username\"),\n    password=secret.field(\"password\"),\n) as session:\n    ...\n```\n\n### Google Cloud Secret Manager\n\nInstall with `pip install mstr-rest-requests[gcp]`.  Authentication uses\n[Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials).\n\n#### Single-value secrets\n\n```python\nfrom mstr.requests.credentials.gcp import secret_manager\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=\"https://demo.microstrategy.com/MicroStrategyLibrary/api/\",\n    username=secret_manager(\"my-project\", \"mstr-username\"),\n    password=secret_manager(\"my-project\", \"mstr-password\"),\n) as session:\n    ...\n```\n\n#### Multi-field secrets\n\n```python\nfrom mstr.requests.credentials.gcp import SecretManagerSecret\n\nsecret = SecretManagerSecret(\"my-project\", \"mstr-connection\")\n\nwith AuthenticatedMSTRRESTSession(\n    base_url=secret.field(\"base_url\"),\n    username=secret.field(\"username\"),\n    password=secret.field(\"password\"),\n) as session:\n    ...\n```\n\n## Session handling\n\n### Checking session state\n\n```python\nsession.has_session()      # True if an auth token is present\nsession.get_session_info() # GET /sessions\nsession.extend_session()   # PUT /sessions (prolongs the session)\nsession.get_userinfo()     # GET /sessions/userInfo\n```\n\n### Serialisation and restoration\n\nA session can be serialised to JSON and later restored, which is useful for\npassing sessions between processes:\n\n```python\ndata = session.json()\n\n# Later, in another process:\nrestored = MSTRRESTSession.from_dict(json.loads(data))\n```\n\n### Projects\n\n```python\nsession.load_projects()\nproject_id = session.get_project_id(\"My Project\")\nresponse = session.get(\"reports/abc123\", project_id=project_id)\n```\n\n## Making requests\n\n`MSTRRESTSession` extends `requests.Session`, so the full requests API is\navailable. Two extra keyword arguments are added to every request method:\n\n- `include_auth` (default `True`) -- attach the `X-MSTR-AuthToken` header.\n- `project_id` -- attach the `X-MSTR-ProjectID` header for project-scoped\n  endpoints.\n\n```python\nresponse = session.get(\"reports/abc123\", project_id=\"B7CA92...\")\n```\n\n## Exceptions\n\nAll API error responses are translated into typed exceptions:\n\n| Exception                          | Error codes            | Trigger                              |\n|------------------------------------|------------------------|--------------------------------------|\n| `LoginFailureException`            | ERR003                 | Authentication error                 |\n| `IServerException`                 | ERR002, ERR0013        | IServer error or unreachable         |\n| `ResourceNotFoundException`        | ERR004                 | Resource not found                   |\n| `InvalidRequestException`          | ERR005, ERR006, ERR007 | Missing or invalid input             |\n| `SessionException`                 | ERR009                 | Session invalid or timed out         |\n| `InsufficientPrivilegesException`  | ERR0014, ERR0017       | Insufficient privileges / permission |\n| `ObjectAlreadyExistsException`     | ERR0015                | Object already exists                |\n| `MSTRUnknownException`             | --                     | Response missing error code          |\n| `MSTRException`                    | Everything else        | Base class / catch-all               |\n\n```python\nfrom mstr.requests.rest.exceptions import LoginFailureException\n```\n\n## License\n\nApache 2.0 -- see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulbailey%2Fmstr-rest-requests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulbailey%2Fmstr-rest-requests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulbailey%2Fmstr-rest-requests/lists"}