Skip to content

fix(linkedin): remove read actions requiring unavailable r_member_social scope#291

Merged
Ilikecarpet merged 8 commits intomasterfrom
om/linkedin-remove-read-actions
May 1, 2026
Merged

fix(linkedin): remove read actions requiring unavailable r_member_social scope#291
Ilikecarpet merged 8 commits intomasterfrom
om/linkedin-remove-read-actions

Conversation

@Ilikecarpet
Copy link
Copy Markdown
Contributor

Description 📝

  • Purpose: This PR addresses failing API calls in the LinkedIn integration by removing actions (get_post, get_posts, get_comments, get_reactions) that depend on the r_member_social scope, which is unavailable to the current OAuth application.
  • Approach: The fix involves removing the non-functional actions, their corresponding configurations in config.json, the associated Python action handlers, and all related unit tests. The r_member_social scope is also removed from the list of requested authentication scopes.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Updates
👉 Removed get_post, get_posts, get_comments, and get_reactions from linkedin/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 👓

  • Project and all contained modules builds successfully
  • Self-/dev-tested
  • Unit/UI/Automation/Integration tests provided where applicable
  • Code is written to standards
  • Appropriate documentation written (code comments, internal docs)

…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.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

🔍 Integration Validation Results

Commit: d8c23b23bb9e1f23d79ab65742aa9139f758a25b · refactor(linkedin): align unit tests with writing-unit-tests skill
Updated: 2026-05-01T03:55:29Z

Changed directories: linkedin

Check Result
Structure ⚠️ Passed with warnings
Code ✅ Passed
Tests ✅ Passed
README ✅ Passed
Version ✅ Passed
⚠️ Structure Check output
Validating 1 integration(s)...

============================================================
Integration: linkedin
============================================================

Warnings (1):
  ⚠️ Potentially unused scopes (please verify): w_member_social, email

============================================================
SUMMARY
============================================================
Integrations validated: 1
Total errors: 0
Total warnings: 1

⚠️ Validation passed with warnings - please review
✅ Code Check output

[notice] A new release of pip is available: 26.0.1 -> 26.1
[notice] To update, run: pip install --upgrade pip
----------------------------------------
Checking: linkedin
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   ✅ Fetch patterns OK

========================================
✅ CODE CHECK PASSED
========================================
✅ Tests Check output

Integration   Tests  Coverage        Status
-------------------------------------------
linkedin     38/38       83%      ✅ Passed
-------------------------------------------
Total        38/38            ✅ All passed

✅ Tests passed: linkedin
✅ README Check output
========================================
✅ README CHECK PASSED
========================================
✅ Version Check output
✅ linkedin: 2.0.0 → 3.0.0 (major bump)

========================================
✅ VERSION CHECK PASSED
========================================

- 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
Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.pylinkedin/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/ ⚠️ (0 collected).

…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.
@Ilikecarpet Ilikecarpet requested a review from TheRealAgentK May 1, 2026 01:51
- 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.
Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Ilikecarpet Ilikecarpet merged commit f9746de into master May 1, 2026
3 checks passed
@Ilikecarpet Ilikecarpet deleted the om/linkedin-remove-read-actions branch May 1, 2026 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants