fix(linkedin): remove read actions requiring unavailable r_member_social scope#291
Conversation
…ial scope The get_post, get_posts, get_comments, and get_reactions actions all depend on r_member_social, which is part of LinkedIn's Community Management API and not granted to the current OAuth app. Calls were failing with 400 ILLEGAL_ARGUMENT. Removing the actions, their config entries, the scope from auth.scopes, and the corresponding tests so the integration only exposes actions that actually work with w_member_social + OIDC scopes.
🔍 Integration Validation ResultsCommit: Changed directories:
|
- Pin autohive-integrations-sdk~=2.0.0 - All context.fetch() call sites now access .data on the returned FetchResponse - All error returns converted from ActionResult-with-error-shape to ActionError - Removed `details` field from every action's output schema (no longer returned now that errors are ActionError) - Bumped integration version 2.0.0 -> 3.0.0 (combines SDK upgrade + read-action removal, both major) - Removed unused `quote` import from tests; tests now wrap fetch returns in FetchResponse and assert ResultType.ACTION_ERROR for failure paths
TheRealAgentK
left a comment
There was a problem hiding this comment.
Thanks for cleaning up the unavailable-scope actions — the production fix itself looks correct.
However, this PR ships with no unit tests collected by CI and no integration tests at all, which I'd like to see addressed before merge.
Unit tests
The file linkedin/tests/test_linkedin.py contains real pytest unit tests (MockExecutionContext, pytestmark = pytest.mark.asyncio, mocked context.fetch), but it uses the legacy filename. Our pyproject.toml is configured with:
python_files = ["test_*_unit.py"]
addopts = "-m unit"So test_linkedin.py is silently skipped by both CI and local pytest runs. I verified locally — pytest linkedin/ -v collects 0 tests on this branch. After this PR merges, LinkedIn will have effectively zero test coverage in CI.
Action required: rename linkedin/tests/test_linkedin.py → linkedin/tests/test_linkedin_unit.py and add pytestmark = [pytest.mark.unit, pytest.mark.asyncio] so the surviving tests are picked up. See the writing-unit-tests skill for the exact convention.
Integration tests
There is no linkedin/tests/test_linkedin_integration.py. Given that this PR removes 4 actions because of an OAuth scope issue that only manifests against the live API, an integration test (gated by @pytest.mark.integration, env-var-driven, excluded from CI by default) would have caught the broken scope earlier and protected the remaining create_post / create_comment / update_post actions from a similar regression.
Action required: add linkedin/tests/test_linkedin_integration.py covering at least the surviving write actions, following the writing-integration-tests skill. Read-only smoke coverage is fine; destructive ones can be @pytest.mark.destructive and gated.
Other notes
- Branch name doesn't follow the
<type>/<issue-number>/<short-description>convention from AGENTS.md. - No linked issue (
Closes #N).
Local CI status: validate_integration.py ✅, check_code.py ✅, ruff check ✅, ruff format ✅, pytest linkedin/
…s checks Remove create_comment, delete_comment, create_reaction, and delete_reaction because they require LinkedIn's Community Management API product. The "Share on LinkedIn" product (which is what the app has) only grants the post-creation slice of w_member_social — the Reactions API and Comments API return HTTP 403 ACCESS_DENIED for partnerApiReactions / partnerApiComments. Mirrors the read-action removal in 91b42ea. Add response.status >= 400 checks to update_post and delete_post. Without these, the actions silently reported success on any HTTP status, masking real API failures and leaving posts on the user's profile when LinkedIn rejected the call. Add linkedin/tests/test_linkedin_integration.py with end-to-end live-API coverage for the remaining 6 actions (get_user_info plus post lifecycles for text, image, article, and reshare). Token comes from the LINKEDIN_ACCESS_TOKEN env var; documented in .env.example.
Resolves CI formatting check failure. No behavioral changes.
CI's python_files=["test_*_unit.py"] glob wasn't matching the existing test_linkedin.py, so the unit suite was silently skipping in every CI run. - Rename test_linkedin.py → test_linkedin_unit.py to match the glob - Add pytestmark = [pytest.mark.unit, pytest.mark.asyncio] so -m unit picks it up - Add tests/conftest.py to inject tests/ into sys.path for `from context import …` - Rewrite tests/context.py to load linkedin.py via importlib.util.spec_from_file_location instead of `from linkedin import linkedin`, which collided with the empty linkedin/__init__.py package when pytest ran from the repo root - Loosen three input-validation tests (too_many_images, missing_file_content, missing_file_content_type) to accept either ACTION_ERROR or VALIDATION_ERROR since SDK 2.0 schema validation now runs before the action handler
Resolves the config-code sync warnings from CI. Required schema fields were being read with inputs.get() (which silently returns None on missing keys) instead of inputs[...] (which raises). Behaviorally equivalent because the SDK validates required fields before the handler runs, so .get() never actually returned None — but the code now matches the schema contract. Affected: share_article (article_url, article_title), reshare_post (original_post_urn), update_post (post_urn, commentary), delete_post (post_urn). Optional params (commentary, author_id, visibility, etc.) keep .get() with defaults.
- Inline importlib boilerplate per the skill template; drop the context.py shim and reduce conftest.py to a docstring-only marker (the validator requires conftest.py or context.py to exist). - Replace the bespoke MockExecutionContext class with a MagicMock + AsyncMock mock_context fixture; populate ctx.auth with the PlatformOauth2 envelope expected by the SDK. - Reorganise tests into one class per action (TestGetUserInfo, TestCreatePost, TestShareArticle, TestResharePost, TestUpdatePost, TestDeletePost) and add helper-function classes for validate_file_input and encode_urn. - Per-test FetchResponse responses via return_value / side_effect rather than a centralised URL router. - Add error-status coverage for update_post / delete_post and request-verification tests across all actions; total 22 -> 38.
TheRealAgentK
left a comment
There was a problem hiding this comment.
LGTM now.
PR was more or less fine after @Ilikecarpet's last round of changes, only work I did was to update the tests to our modern standards and verify locally with unit and e2e test flows.
Description 📝
get_post,get_posts,get_comments,get_reactions) that depend on ther_member_socialscope, which is unavailable to the current OAuth application.config.json, the associated Python action handlers, and all related unit tests. Ther_member_socialscope is also removed from the list of requested authentication scopes.Type of change
Updates
👉 Removed
get_post,get_posts,get_comments, andget_reactionsfromlinkedin/config.json.👉 Deleted the associated action handlers from
linkedin/linkedin.py.👉 Removed corresponding tests from
linkedin/tests/test_linkedin.py.Test plan 🧪
The remaining actions in the integration should continue to function as expected. Testing should confirm that creating/updating/deleting posts, comments, and reactions still works.
Author(s) to check 👓