Harden Google Workspace gws exports (#772)

This commit is contained in:
Chris S
2026-05-07 15:07:57 -04:00
committed by GitHub
parent e16ea149aa
commit ca1b774dd9
3 changed files with 57 additions and 3 deletions
+1
View File
@@ -7,6 +7,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu
- Feat: TypeScript extraction parity -- interface, enum, type alias, and module-level const nodes extracted; new_expression emits calls edges; parity with Java/C# class_types (#708)
- Feat: Quarto (`.qmd`) file support -- routed through existing Markdown extractor; Quarto executable code blocks (` ```{python} `) extracted as code nodes (#761)
- Feat: optional Google Workspace shortcut export for headless extraction -- `graphify extract ./docs --google-workspace` converts `.gdoc`, `.gsheet`, and `.gslides` files into Markdown sidecars with the `gws` CLI before semantic extraction; account email pseudonymized via SHA256 hash; `[google]` extra adds Sheets table rendering support (#752)
- Fix: Google Workspace exports now run `gws` from the sidecar output directory with a relative `-o` path, matching `gws` path validation and avoiding failures when extracting a corpus outside the current working directory.
- Feat: AWS Bedrock backend -- `graphify extract ./docs --backend bedrock`; credentials via standard AWS provider chain (AWS_PROFILE, AWS_REGION, IAM roles, SSO); model via GRAPHIFY_BEDROCK_MODEL (default anthropic.claude-3-5-sonnet-20241022-v2:0); `[bedrock]` extra adds boto3 (#757)
## 0.7.8 (2026-05-06)
+8 -3
View File
@@ -100,12 +100,17 @@ def _run_gws_export(file_id: str, mime_type: str, output: Path, resource_key: st
)
params: dict[str, str] = {"fileId": file_id, "mimeType": mime_type}
if resource_key:
params["resourceKey"] = resource_key
# Drive resource keys are sent via X-Goog-Drive-Resource-Keys. The current
# gws export command has no custom-header flag, so do not pass resourceKey
# as an unsupported query parameter.
_ = resource_key
output = output.resolve()
output.parent.mkdir(parents=True, exist_ok=True)
timeout = int(os.environ.get("GRAPHIFY_GOOGLE_WORKSPACE_TIMEOUT", "120"))
result = subprocess.run(
[exe, "drive", "files", "export", "--params", json.dumps(params), "-o", str(output)],
[exe, "drive", "files", "export", "--params", json.dumps(params), "-o", output.name],
capture_output=True,
cwd=output.parent,
text=True,
timeout=timeout,
)
+48
View File
@@ -1,4 +1,5 @@
from pathlib import Path
import json
import graphify.google_workspace as gw
@@ -73,6 +74,53 @@ def test_convert_gsheet_uses_xlsx_markdown_callback(tmp_path, monkeypatch):
assert "## Sheet: Main" in out.read_text(encoding="utf-8")
def test_run_gws_export_uses_output_directory_as_cwd(tmp_path, monkeypatch):
output = tmp_path / "converted" / "doc.md"
calls = []
class Result:
returncode = 0
stdout = ""
stderr = ""
def fake_run(cmd, **kwargs):
calls.append((cmd, kwargs))
return Result()
monkeypatch.setattr(gw.shutil, "which", lambda name: "/usr/local/bin/gws")
monkeypatch.setattr(gw.subprocess, "run", fake_run)
gw._run_gws_export("doc-123", "text/markdown", output)
assert output.parent.exists()
cmd, kwargs = calls[0]
assert kwargs["cwd"] == output.parent.resolve()
assert cmd[:4] == ["/usr/local/bin/gws", "drive", "files", "export"]
assert cmd[-2:] == ["-o", "doc.md"]
def test_run_gws_export_does_not_send_resource_key_as_query_param(tmp_path, monkeypatch):
output = tmp_path / "converted" / "doc.md"
calls = []
class Result:
returncode = 0
stdout = ""
stderr = ""
def fake_run(cmd, **kwargs):
calls.append(cmd)
return Result()
monkeypatch.setattr(gw.shutil, "which", lambda name: "/usr/local/bin/gws")
monkeypatch.setattr(gw.subprocess, "run", fake_run)
gw._run_gws_export("doc-123", "text/markdown", output, resource_key="rk-1")
params = json.loads(calls[0][calls[0].index("--params") + 1])
assert params == {"fileId": "doc-123", "mimeType": "text/markdown"}
def test_google_workspace_enabled_env(monkeypatch):
monkeypatch.setenv("GRAPHIFY_GOOGLE_WORKSPACE", "yes")
assert gw.google_workspace_enabled()