fix(adms): align API surface with live ADMS wire format - #192
ShiwaliKusum wants to merge 8 commits into
Conversation
|
I766515 seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
|
PR description is not following our template. Only raise PRs to us once it's complete. |
Adds the SDK Module Review skill to this repository: ## What this PR adds **20 deterministic checks** (no LLM calls in CI): - secrets, license-spdx, disclosure, hardcode, telemetry, docs, bdd, patterns, versioning + BREAKING family, commits, errors-logging, testing-depth, http-hygiene, concurrency, deps-supply, deletion-hygiene, constants, binding-shape, quality-gate-parity, pr-size **Rule tiers:** SHADOW | FLAG | BLOCK | BLOCK_LOCKED, configured in `.claude/config/rules.yaml` **BLOCK_LOCKED rules cannot be suppressed:** - SEC-* (all secrets), HC-03 (SAP-internal URL leak), DIS-06 (internal artifactory), LIC-01/02 (SPDX headers), BND-02 (BTP token URL concat), BND-05 (binding logs credentials), BREAKING-* (all breaking-change declarations) **REUSE.toml aggregate exemption** — this repo uses REUSE.toml at root, so per-file SPDX rules are baseline-exempted automatically. **Cross-language BDD parity** — module-aliases.yaml seeded with `dms ↔ documentmanagement` (Java sibling). **4 PR signals posted per run:** 1. Inline comments per finding 2. Aggregated summary comment 3. GitHub check-run (Checks tab) 4. Status label (`sdk-review: ✅ passed` / `❌ blocked` / `⚠️ flagged`) **Idempotent re-runs:** HTML markers let subsequent runs replace prior artifacts rather than duplicate them. ## Structure - `.claude/scripts/`: 20 check-*.sh + orchestrate.sh + aggregate.sh - `.claude/scripts/lib/`: 12 shared libs (2 Python AST + 10 bash) - `.claude/config/`: rules.yaml, module-aliases.yaml, baseline.json - `.github/workflows/sdk-module-review.yml`: auto-trigger on every PR - `.github/workflows/sdk-skill-isolation-check.yml`: validates sub-PRs - `docs/PR-REVIEW.md`: user-facing docs - `docs/BRANCH-PROTECTION-SETUP.md`: admin guide for required-check config - `tests/sdk-review/`: 57 bats tests + 6 fixtures (placeholder secrets, not real credentials) - `CONTRIBUTING.md`: amended — sdk-module-review is required before review ## Validation - 57/57 bats tests passing - shellcheck clean on all bash scripts - E2E on 5 real PRs (#196, #191, #192, #185 in this repo + Java jv#9): zero false positives observed - Self-test on this PR: 0 BLOCK, 0 FLAG (skill correctly skips its own files) - Flagship BND-02 finding verified on Java new-module PR (token URL concat) ## Rollout Recommended SHADOW → FLAG → BLOCK progression, 2 weeks each. See `docs/BRANCH-PROTECTION-SETUP.md`. ## Note on test fixtures `tests/sdk-review/fixtures/secrets-*.diff` contain intentional placeholder strings that match secret regexes (e.g. `AKIATESTFIXTUREXXXXX`, `eyJTESTFIXTURE...`) so the check-secrets rule can be unit-tested. These are NOT real credentials. Ref: https://jira.tools.sap/browse/AFSDK-3937
Mirrors cloud-sdk-java contrib-java/adms commit e5dd1da's wire-format
audit. The Java audit identified 12 fixes against the canonical CDS
sources + live ADMS tenant. Cross-verified Python state vs CDS:
- 7 fixes were already correct in Python (UpdateDocumentInput fields,
RestoreContentVersion envelope, DeleteContentVersion body shape,
DownloadDocument GET function, StartJob payload, JobStatus function,
LateHostBusinessObjectNodeID casing).
- 5 namespace-prefix fixes were genuinely missing (lock, unlock,
complete_multipart_upload, generate_upload_urls, mark_default) —
Python used the short form which CAP accepts leniently but is not
the canonical OData V4 wire format.
For cross-SDK consistency with Java, ALL 12 bound/unbound action paths
now use the fully-qualified com.sap.adm.{DocumentService,AdminService,
ConfigurationService}.X form:
DocumentService bound actions on DocumentRelation:
UpdateDocument, CompleteMultipartUpload,
RestoreDocumentContentVersion, DeleteDocumentContentVersion,
LockDocumentAndRelation, UnlockDocumentAndRelation,
GenerateDocumentUploadURLs, DownloadDocument (function)
DocumentService unbound:
StartJob, JobStatus (function)
AdminService unbound:
StartJob, JobStatus (function)
ConfigurationService bound on DocumentTypeBusinessObjectTypeMap:
markDefault
Test changes:
- Tightened 7 substring assertions in test_client.py to include the
namespace prefix so the wire contract is captured in tests.
Also includes prior work on this branch:
- extra_headers support on sync + async HTTP verbs (for x-subaccount-id
header on ApplicationTenant operations)
- subaccount_id parameter on all 4 ApplicationTenant config methods
No API surface changes, no model changes, no behavioural changes —
purely wire-protocol alignment with Java commit e5dd1da.
Interactive CLI for testing all ADMS APIs against a real ADM instance. Used during this PR's development to verify each of the 12 wire-format fixes returns the expected response from the live tenant. WILL BE REMOVED BEFORE MERGE — kept in this PR only as a debugging aid so reviewers can reproduce the live-tenant verification if desired. Usage: set -a && source .env.adms && set +a .venv/bin/python scripts/adms_cli.py
- Remove MimeTypePolicy from __init__.py (renamed to FileExtensionPolicy in _models.py) - Rename FileExtensionPolicy entity set to DocumentTypeFileExtensionPolicy - Drop get_file_extension_policy by UUID; delete now uses composite key (DocumentTypeID + FileExtension) - Fix build_doctype_botype_map_key_path to use composite key (DocumentTypeID + BusinessObjectNodeTypeUniqueID) - Update get_type_mapping / delete_type_mapping / mark_default to accept composite key params - Make doc_content_version_id optional in get_download_url (omit parentheses content when None) - Drop post-update GET in update_document; return partial response from UpdateDocument action directly - Fix X-SubaccountId header casing - Align job API namespace constants with canonical server wire format - Expand adms_cli.py with rfu (full upload) command and additional fixes from live tenant testing
…lt type mapping The ADM DocumentTypeBusinessObjectTypeMap entity uses a composite key (DocumentTypeID + BusinessObjectNodeTypeUniqueID). The previous single-argument signature used a fabricated DocumentTypeBOTypeMapID that was never accepted by the service (HTTP 400), so this signature change is a bug-fix, not a breaking API change. Added note in docstrings to clarify.
86e7359 to
fa0929c
Compare
There was a problem hiding this comment.
Several lines in this file seems to exceed 88 characters substantially, which is probably why pre-commit is failing.
| return {"X-SubaccountId": subaccount_id} if subaccount_id else None | ||
|
|
||
|
|
||
| def _quote_guid(value: str) -> str: |
There was a problem hiding this comment.
It seems that this method is no longer used.
|
The new |
|
New methods |
Description
Aligns the ADMS Python SDK API surface with the live ADM service wire format. Several entity paths, key structures, and method signatures were incorrect — they compiled but failed at runtime (HTTP 400/404) against the real service.
Configuration API fixes:
DocumentTypeBusinessObjectTypeMapuses a composite key (DocumentTypeID+BusinessObjectNodeTypeUniqueID), not a single UUID.get_type_mapping,delete_type_mapping, andmark_defaultupdated accordingly.FileExtensionPolicyentity set renamed fromFileExtensionPolicytoDocumentTypeFileExtensionPolicy(matches$metadata). Model fields corrected toDocumentTypeID+FileExtensioncomposite key;get_file_extension_policy(uuid)removed as no such UUID key exists in ADM.CreateDocumentTypeBoTypeMapInputwire field names corrected fromDocumentTypeId/BusinessObjectNodeTypeUniqueIdtoDocumentTypeID/BusinessObjectNodeTypeUniqueID.MimeTypePolicyremoved from public__init__exports (no longer referenced by any public model).Document API fixes:
update()(sync + async): removed the implicit follow-up GET — theUpdateDocumentaction returns the partial response directly from ADM; callers who need the full document should callget()explicitly.get_download_url()(sync + async):doc_content_version_idis now optional (None→DownloadDocument()for latest version), matching the ODataCore.OptionalParameterannotation.Job API fixes:
StartJobandJobStatuscalled without namespace prefix (unbound action/function imports do not use namespace prefix per OData spec).Related Issue
Closes #https://jira.tools.sap/browse/RBSADMS-47
Type of Change
How to Test
set -a && source .env.adms && set +auv run pytest tests/adms/unit/ -vuv run pytest tests/adms/integration/ -vcfl,cmg,cmd,cgf,jz,jscommands work against the live tenant usingscripts/adms_cli.pyChecklist
Breaking Changes
get_type_mappinganddelete_type_mappingnow require two arguments (document_type_id,business_object_node_type_unique_id) instead of one. However, the previous single-argument version accepted aDocumentTypeBOTypeMapIDthat the ADM service never supported — every call returned HTTP 400. Since the old signature was non-functional, this is treated as a bug fix rather than a breaking API change.get_file_extension_policy(uuid)is removed. The ADM entity has no UUID primary key; policies are identified by(DocumentTypeID, FileExtension). The old method would have always returned HTTP 404.update()no longer performs an implicit GET after updating a document. The return value is now the partial action response from ADM (only changed fields). Callers requiring the full document after an update should calldocuments.get()explicitly.Additional Notes
All fixes were validated against a live ADM playground tenant. The
scripts/adms_cli.pyinteractive CLI (kept locally, not included in this PR) was used for end-to-end verification of each endpoint.