Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0b79d0f
fix: authenticate inbound LINE media before decryption
meramsey Oct 20, 2026
17ae6dc
fix: attach detected metadata to inbound LINE images
meramsey Oct 20, 2026
298dfad
test: make signing and cancellation checks race-stable
meramsey Oct 20, 2026
695d6d9
fix: resolve public LINE IDs before creating DM portals
meramsey Oct 20, 2026
09a8685
fix: serialize QR login operations and preserve deadline errors
meramsey Oct 20, 2026
6e333e5
diagnostics: preserve sanitized QR login rejection details
meramsey Oct 21, 2026
20e3540
diagnostics: audit QR identity compatibility and clarify session fail…
meramsey Oct 21, 2026
596334a
line: structured authentication errors and extended cooldown handling
meramsey Oct 22, 2026
ffb62b5
build: place extra build flags before package path
meramsey Oct 22, 2026
00a6ccc
test: establish native heap pressure without redundant key decoding
meramsey Oct 21, 2026
c0121cf
test: make concurrency checks deterministic and isolate vector output
meramsey Oct 21, 2026
c4ffe53
fix: preserve outbound cancellation and LINE send errors
meramsey Oct 20, 2026
c6cf461
fix: preserve safe LINE authentication details and enforce cooldowns
MikeRijkenz Oct 29, 2026
bde3468
fix: validate LINE lookup identities without folding opaque IDs
MikeRijkenz Oct 29, 2026
971a828
test: cover DM reopening and passwordless QR reconnects
meramsey Oct 20, 2026
1b0db13
ci: restore bounded test validation and coverage gates
MikeRijkenz Oct 29, 2026
e18d9f4
fix: serialize account logins and classify session failures
MikeRijkenz Oct 29, 2026
46a2e79
fix: bound provider text and avoid empty contact searches
MikeRijkenz Oct 29, 2026
dba644c
test: cover upstream E2EE and media metadata paths
MikeRijkenz Oct 29, 2026
0b151e0
ci: keep test caches inside the isolated work area
MikeRijkenz Oct 29, 2026
c1d2fad
fix: enforce cooldowns on background token recovery
MikeRijkenz Oct 29, 2026
8811f31
test: preserve V2 group encryption fallback coverage
MikeRijkenz Oct 29, 2026
d57862a
docs: trace chat sync and outbound authentication diagnostics
meramsey Oct 20, 2026
022678d
diagnostics: identify synchronization triggers and document chat flows
meramsey Oct 20, 2026
bbee6c0
Merge remote-tracking branch 'origin/main' into rebuild/upstream-stab…
MikeRijkenz Oct 29, 2026
f7d8766
test: bridge link preview images through Matrix media upload
MikeRijkenz Oct 29, 2026
e181e0d
test: restore opaque identity and recipient audit coverage
meramsey Oct 29, 2026
b68db47
test: verify stored group key spec version
MikeRijkenz Oct 29, 2026
4738543
ci: prevent fork builds from pushing Beeper images
MikeRijkenz Oct 29, 2026
78752cb
fix: honor retry guidance across authentication transports
MikeRijkenz Oct 29, 2026
7c4303c
fix: preserve safe reconnect errors and release login claims
MikeRijkenz Oct 29, 2026
e50154b
build: disable unreliable linked-worktree VCS stamping
MikeRijkenz Oct 29, 2026
f36c646
fix: restore friendly LINE login command aliases
MikeRijkenz Oct 29, 2026
07badf9
merge: update LINE stabilization with current upstream main
MikeRijkenz Oct 29, 2026
18eb2a3
docs: record upstream integration status
MikeRijkenz Oct 29, 2026
81f5021
docs: clarify existing upstream PR patch coverage
MikeRijkenz Oct 30, 2026
4971ee3
docs: add PR 297 reviewer comparison, replay matrix and risk assessment
MikeRijkenz Nov 3, 2026
abed6e3
Merge branch 'main' into upstream/line-stabilization-20261029
meramsey Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/coverage-baseline.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Max of historical development baseline and measured upstream baseline at 913362278cb8d7b39b90e04be3d54b43e3aba843.
# package covered total non_generated_covered non_generated_total
github.com/beeper/line/cmd/matrix-line 0 3 0 3
github.com/beeper/line/pkg 235 736 235 736
github.com/beeper/line/pkg/connector 1537 4433 1537 4433
github.com/beeper/line/pkg/connector/handlers 368 985 368 985
github.com/beeper/line/pkg/e2ee 223 608 223 608
github.com/beeper/line/pkg/line 419 1567 419 1567
github.com/beeper/line/pkg/line/password 0 26 0 26
github.com/beeper/line/pkg/line/secret 0 7 0 7
github.com/beeper/line/pkg/ltsm 171289 404716 545 1061
69 changes: 64 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ jobs:
uses: docker/setup-buildx-action@v3

- name: Login to registry
if: github.event_name == 'push' && github.repository == 'beeper/line'
uses: docker/login-action@v3
with:
registry: ${{ secrets.CI_REGISTRY }}
Expand All @@ -88,21 +89,22 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
cache-from: ${{ env.CI_REGISTRY_IMAGE }}:latest
cache-from: type=gha,scope=line-linux-amd64
cache-to: type=gha,mode=max,scope=line-linux-amd64
pull: true
file: Dockerfile
tags: |
${{ env.CI_REGISTRY_IMAGE }}:${{ github.sha }}
${{ env.CI_REGISTRY_IMAGE }}:${{ github.sha }}-amd64
push: true
${{ github.event_name == 'push' && github.repository == 'beeper/line' && format('{0}:{1}', env.CI_REGISTRY_IMAGE, github.sha) || format('line-ci:{0}', github.sha) }}
${{ github.event_name == 'push' && github.repository == 'beeper/line' && format('{0}:{1}-amd64', env.CI_REGISTRY_IMAGE, github.sha) || format('line-ci:{0}-amd64', github.sha) }}
push: ${{ github.event_name == 'push' && github.repository == 'beeper/line' }}

deploy-docker:
runs-on: ubuntu-latest
needs:
- lint
- build
- build-docker
if: github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/main' && github.repository == 'beeper/line'
steps:
- name: Login to Beeper Docker registry
uses: docker/login-action@v3
Expand All @@ -125,3 +127,60 @@ jobs:
BEEPER_DEV_ADMIN_NIGHTLY_PASS: "${{ secrets.BEEPER_DEV_ADMIN_NIGHTLY_PASS }}"
BEEPER_STAGING_ADMIN_NIGHTLY_PASS: "${{ secrets.BEEPER_STAGING_ADMIN_NIGHTLY_PASS }}"
BEEPER_PROD_ADMIN_NIGHTLY_PASS: "${{ secrets.BEEPER_PROD_ADMIN_NIGHTLY_PASS }}"

test:
name: Test (${{ matrix.mode }})
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
mode: [normal, race, coverage]
env:
GOMAXPROCS: "4"
TEST_PACKAGE_PARALLELISM: "2"
TEST_TIMEOUT: 10m
TEST_JSON: "1"
TEST_OUTPUT_DIR: ${{ github.workspace }}/.opencode-work/test-ci-${{ matrix.mode }}
GOPATH: ${{ github.workspace }}/.opencode-work/gopath
GOCACHE: ${{ github.workspace }}/.opencode-work/go-build-cache
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
id: go
with:
go-version: "1.26"
cache: false
- name: Install libolm
run: sudo apt-get update && sudo apt-get install -y libolm-dev
- name: Identify native test ABI
id: native
run: echo "abi=$(gcc -dumpfullversion)-$(pkg-config --modversion olm)" >> "$GITHUB_OUTPUT"
- name: Cache Go modules
uses: actions/cache@v4
with:
path: ${{ env.GOPATH }}/pkg/mod
key: test-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
- name: Cache compiled tests by instrumentation mode
uses: actions/cache@v4
with:
path: ${{ env.GOCACHE }}
key: test-build-${{ runner.os }}-${{ runner.arch }}-${{ steps.go.outputs.go-version }}-${{ steps.native.outputs.abi }}-${{ matrix.mode }}-${{ hashFiles('go.sum') }}-${{ hashFiles('**/*.go', 'pkg/ltsm/data/*') }}
restore-keys: |
test-build-${{ runner.os }}-${{ runner.arch }}-${{ steps.go.outputs.go-version }}-${{ steps.native.outputs.abi }}-${{ matrix.mode }}-${{ hashFiles('go.sum') }}-
- name: Verify LINE login aliases for release
if: matrix.mode == 'normal'
run: TEST_RUN='^TestRegisteredLineLoginCommandDispatch$' bash scripts/test.sh fast ./pkg/connector
- name: Run validation
run: bash scripts/test.sh "${{ matrix.mode }}"
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.mode }}
path: |
${{ env.TEST_OUTPUT_DIR }}/coverage.out
if-no-files-found: warn
retention-days: 7
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@

# internal tools
/tools

# OpenCode-only validation artifacts and continuity records
/.opencode-work/
/CONTINUITY.md
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Based on the [mautrix-twilio](https://github.com/mautrix/twilio) bridge
> need to log out of the bridge first as the bridge will try to automatically
> log back in and invalidate the LINE Chrome session again.

For direct-chat identifiers, synchronization triggers, outbound-message diagnostics,
and QR login troubleshooting, see [the debugging guide](readme/DEBUGGING.md).

## Features

- [x] Messages
Expand Down
9 changes: 7 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#!/bin/sh
MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }' | head -n1)
GO_LDFLAGS="-s -w -X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date -Iseconds`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'"
go build -ldflags="$GO_LDFLAGS" ./cmd/matrix-line "$@"
if [ -n "${SOURCE_DATE_EPOCH:-}" ]; then
BUILD_TIME=$(date -u -Iseconds -d "@$SOURCE_DATE_EPOCH")
else
BUILD_TIME=$(date -Iseconds)
fi
GO_LDFLAGS="-s -w -X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=$BUILD_TIME' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'"
go build -buildvcs=false -ldflags="$GO_LDFLAGS" "$@" ./cmd/matrix-line
43 changes: 43 additions & 0 deletions docs/FEATURE_PARITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Feature parity with the previous development checkpoint

Comparison baseline: checkpoint `910b4b3dceceb1dcd0e0b34e805ffc83d13d594f`
and known working tree `4eec1754b7916cbeed622529e5c9fb9ca129f6d2`, compared
with upstream-first release source `e50154bda1f0ac2632574048760d1bee18e5331a`.
The new source is a separate upstream integration history, so ancestry alone is
not evidence of parity. Feature and test paths were reviewed directly.

| Historical feature | Source | Current implementation | Status / action | Coverage |
| --- | --- | --- | --- | --- |
| Friendly `login qr`, `login email`, `login help` | `4e9b184` | `pkg/connector/login_command.go`; registered in `LineConnector.Init` | Missing in rebuild because custom handler registration was omitted; restored | `pkg/connector/login_command_test.go` uses real framework processor |
| QR auth lifecycle and flow ID | upstream PR #271; `09a8685`, `6e333e5`, `4eec175` | `connector.go`, `login_qr.go`, `pkg/line/qr.go` | Present; alias dispatch is separate | `login_qr_test.go`, `qr_failure_test.go`, `qr_error_test.go` |
| Sanitized provider auth errors and cooldown | `6e333e5`, `596334a`, `4eec175`, `c6cf461`, `c1d2fad`, `7c4303c` | `loginerrors.go`, `login_cooldown.go`, `pkg/line/auth_error.go`, `pkg/line/errors.go` | Present and extended; do not roll back | `login_cooldown_test.go`, `login_error_logging_test.go`, `auth_error_test.go` |
| Public LINE ID resolution before portal creation | `695d6d9` | `userinfo.go`, `resolve_identifier.go` | Present | `resolve_identifier_test.go`, `identity_audit_test.go` |
| MID normalization and opaque case-sensitive IDs | `7615af2`, `05a1607`, `bde3468` | `pkg/line/user_mid.go`, `resolve_identifier.go`, `userinfo.go` | Present, with deliberate preservation of gateway identity case | `user_mid_test.go`, `opaque_mid_test.go`, `resolve_identifier_test.go` |
| Contact lookup validation / empty query safety | `160ac20`, `46a2e79` | `userinfo.go` | Present; validates returned contacts and avoids empty-query enumeration | `resolve_identifier_test.go` |
| Optional sanitized lookup-shape diagnostics | `65a2c02` | No current diagnostics code/config | Removed/superseded from rebuild. Not restored: diagnostics were opt-in but the old response parser/key allowlist is not present for current protocol shapes; requires a fresh privacy review and tests before reintroduction | Historical tests existed; no current coverage |
| Portal creation, canonical reuse, reopen and cancellation | `695d6d9`, `15ff9e4`, `971a828` | `resolve_identifier.go`, bridgev2 portal flow | Present | `resolve_identifier_test.go`, `identity_audit_test.go` |
| Outbound delivery, cancellation, provider error status | `c4ffe53`, `0597689`, `72c7a51` | `send_message.go`, `senderrors.go`, connector status mapping | Present | `send_message_test.go`, `outbound_pipeline_test.go` |
| Inbound handling and sync diagnostics | `022678d`, `d57862a` | `handle_message.go`, `sync.go` and bridge structured logs | Present; current upstream path retained | `handle_message_test.go`, `sync_test.go` |
| Media auth, image metadata, HEIC, audio, stickers, link previews | `0b79d0f`, `17ae6dc`, `e2670d4`, `6f7f92b`, `055d62e`, upstream PR #286 | `media.go`, `pkg/line/publicmedia.go`, handlers | Present in current rebuild | media and handler tests including `media_test.go`, `image_media_test.go`, `text_test.go` |
| Group E2EE spec version / crypto runtime behavior | `c5a432d`, `9be42f2`, `8811f31`, `b68db47` | `e2ee_keys.go`, `pkg/e2ee`, `pkg/ltsm` | Present/current implementation retained | `e2ee_keys_test.go`, `manager_test.go` |
| Test optimization and coverage gates | test optimization PR #1; `a8d80f2`, `1b0db13` | `scripts/test.sh`, `scripts/check_test_coverage.py`, coverage workflow | Present | normal/race/coverage/release modes and coverage gate |
| Build/release reproducibility and native packaging | `ffb62b5`, `e50154b` | `build.sh`, release scripts/docs | Present; exact release artifacts preserved | release validation workflow |

## Intentional differences

- The mautrix-go framework still accepts fully qualified login flow IDs; the
LINE aliases wrap, rather than replace, its standard `login` handler and keep
the framework's permissions, login limits, relogin, and command-state logic.
- QR login remains controlled by `network.qr_login`. The friendly help omits QR
when that option is disabled.
- Historical lookup diagnostics are not blindly restored. Current identity
validation and safe errors remain; any new diagnostics need current-schema
allowlisting and a privacy-focused review.
- No production deployment or database/session changes are part of this work.

## Remaining gaps

- The historical lookup-diagnostics feature needs a fresh implementation if
operational evidence shows it is still needed.
- Live Matrix/LINE behavior must be validated after an operator deploys the
prepared release candidate; this source change does not deploy it.
Loading