matrix-org / matrix-org/matrix-hookshot

Creating a GitLab Issue Room Fails with "issue_iid is invalid"

Open
#394 0 comments 0 reactions 0 assignees View on GitHub
S-Minor T-Defect
Dominant language
TypeScript
Stars
450
Forks
95
Avg merge
1d 2h
Merged PRs (30d)
23

Description

**Describe the bug**

After setting a personal token for my GitLab instance in a DM room with Hookshot, I try to run `gitlab open issue` to create an issue room, but the command fails. The bot sends "Failed to handle command: undefined" and in the log this appears:

```
matrix-hookshot-1 | INFO 11:18:19:647 [AdminRoom] Looking up issue INSTANCENAME PROJECTNAME#NaN
matrix-hookshot-1 | 172.30.0.5 - - [03/Jul/2022:11:18:19 +0000] "PUT /transactions/289995?access_token=REDACTED HTTP/1.1" 200 2 "-" "Synapse/1.61.1"
matrix-hookshot-1 | WARN 11:18:19:666 [GitLabClient] Failed to get issue: Error: Request failed with status code 400
matrix-hookshot-1 | at createError (/bin/matrix-hookshot/node_modules/axios/lib/core/createError.js:16:15)
matrix-hookshot-1 | at settle (/bin/matrix-hookshot/node_modules/axios/lib/core/settle.js:17:12)
matrix-hookshot-1 | at IncomingMessage.handleStreamEnd (/bin/matrix-hookshot/node_modules/axios/lib/adapters/http.js:293:11)
matrix-hookshot-1 | at IncomingMessage.emit (node:events:539:35)
matrix-hookshot-1 | at endReadableNT (node:internal/streams/readable:1345:12)
matrix-hookshot-1 | at processTicksAndRejections (node:internal/process/task_queues:83:21) {
matrix-hookshot-1 | config: {
matrix-hookshot-1 | transitional: {
matrix-hookshot-1 | silentJSONParsing: true,
matrix-hookshot-1 | forcedJSONParsing: true,
matrix-hookshot-1 | clarifyTimeoutError: false
matrix-hookshot-1 | },
matrix-hookshot-1 | adapter: [Function: httpAdapter],
matrix-hookshot-1 | transformRequest: [ [Function: transformRequest] ],
matrix-hookshot-1 | transformResponse: [ [Function: transformResponse] ],
matrix-hookshot-1 | timeout: 0,
matrix-hookshot-1 | xsrfCookieName: 'XSRF-TOKEN',
matrix-hookshot-1 | xsrfHeaderName: 'X-XSRF-TOKEN',
matrix-hookshot-1 | maxContentLength: -1,
matrix-hookshot-1 | maxBodyLength: -1,
matrix-hookshot-1 | validateStatus: [Function: validateStatus],
matrix-hookshot-1 | headers: {
matrix-hookshot-1 | Accept: 'application/json, text/plain, */*',
matrix-hookshot-1 | Authorization: 'Bearer REDACTED',
matrix-hookshot-1 | 'User-Agent': 'matrix-hookshot/1.7.3 (+https://github.com/matrix-org/matrix-hookshot)'
matrix-hookshot-1 | },
matrix-hookshot-1 | baseURL: 'GITLABURL',
matrix-hookshot-1 | method: 'get',
matrix-hookshot-1 | url: 'api/v4/ONLYGROUPNAME/issues/NaN',
matrix-hookshot-1 | data: undefined
matrix-hookshot-1 | },
matrix-hookshot-1 | request: ClientRequest {
matrix-hookshot-1 | _events: [Object: null prototype] {
matrix-hookshot-1 | abort: [Function (anonymous)],
matrix-hookshot-1 | aborted: [Function (anonymous)],
matrix-hookshot-1 | connect: [Function (anonymous)],
matrix-hookshot-1 | error: [Function (anonymous)],
matrix-hookshot-1 | socket: [Function (anonymous)],
matrix-hookshot-1 | timeout: [Function (anonymous)],
matrix-hookshot-1 | prefinish: [Function: requestOnPrefinish]
matrix-hookshot-1 | },
matrix-hookshot-1 | _eventsCount: 7,
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | outputData: [],
matrix-hookshot-1 | outputSize: 0,
matrix-hookshot-1 | writable: true,
matrix-hookshot-1 | destroyed: false,
matrix-hookshot-1 | _last: true,
matrix-hookshot-1 | chunkedEncoding: false,
matrix-hookshot-1 | shouldKeepAlive: false,
matrix-hookshot-1 | maxRequestsOnConnectionReached: false,
matrix-hookshot-1 | _defaultKeepAlive: true,
matrix-hookshot-1 | useChunkedEncodingByDefault: false,
matrix-hookshot-1 | sendDate: false,
matrix-hookshot-1 | _removedConnection: false,
matrix-hookshot-1 | _removedContLen: false,
matrix-hookshot-1 | _removedTE: false,
matrix-hookshot-1 | _contentLength: 0,
matrix-hookshot-1 | _hasBody: true,
matrix-hookshot-1 | _trailer: '',
matrix-hookshot-1 | finished: true,
matrix-hookshot-1 | _headerSent: true,
matrix-hookshot-1 | _closed: false,
matrix-hookshot-1 | socket: TLSSocket {
matrix-hookshot-1 | _tlsOptions: [Object],
matrix-hookshot-1 | _secureEstablished: true,
matrix-hookshot-1 | _securePending: false,
matrix-hookshot-1 | _newSessionPending: false,
matrix-hookshot-1 | _controlReleased: true,
matrix-hookshot-1 | secureConnecting: false,
matrix-hookshot-1 | _SNICallback: null,
matrix-hookshot-1 | servername: 'MYGITLABINSTANCE',
matrix-hookshot-1 | alpnProtocol: false,
matrix-hookshot-1 | authorized: true,
matrix-hookshot-1 | authorizationError: null,
matrix-hookshot-1 | encrypted: true,
matrix-hookshot-1 | _events: [Object: null prototype],
matrix-hookshot-1 | _eventsCount: 10,
matrix-hookshot-1 | connecting: false,
matrix-hookshot-1 | _hadError: false,
matrix-hookshot-1 | _parent: null,
matrix-hookshot-1 | _host: 'MYGITLABINSTANCE',
matrix-hookshot-1 | _readableState: [ReadableState],
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | _writableState: [WritableState],
matrix-hookshot-1 | allowHalfOpen: false,
matrix-hookshot-1 | _sockname: null,
matrix-hookshot-1 | _pendingData: null,
matrix-hookshot-1 | _pendingEncoding: '',
matrix-hookshot-1 | server: undefined,
matrix-hookshot-1 | _server: null,
matrix-hookshot-1 | ssl: [TLSWrap],
matrix-hookshot-1 | _requestCert: true,
matrix-hookshot-1 | _rejectUnauthorized: true,
matrix-hookshot-1 | parser: null,
matrix-hookshot-1 | _httpMessage: [Circular *1],
matrix-hookshot-1 | [Symbol(res)]: [TLSWrap],
matrix-hookshot-1 | [Symbol(verified)]: true,
matrix-hookshot-1 | [Symbol(pendingSession)]: null,
matrix-hookshot-1 | [Symbol(async_id_symbol)]: 749,
matrix-hookshot-1 | [Symbol(kHandle)]: [TLSWrap],
matrix-hookshot-1 | [Symbol(lastWriteQueueSize)]: 0,
matrix-hookshot-1 | [Symbol(timeout)]: null,
matrix-hookshot-1 | [Symbol(kBuffer)]: null,
matrix-hookshot-1 | [Symbol(kBufferCb)]: null,
matrix-hookshot-1 | [Symbol(kBufferGen)]: null,
matrix-hookshot-1 | [Symbol(kCapture)]: false,
matrix-hookshot-1 | [Symbol(kSetNoDelay)]: false,
matrix-hookshot-1 | [Symbol(kSetKeepAlive)]: false,
matrix-hookshot-1 | [Symbol(kSetKeepAliveInitialDelay)]: 0,
matrix-hookshot-1 | [Symbol(kBytesRead)]: 0,
matrix-hookshot-1 | [Symbol(kBytesWritten)]: 0,
matrix-hookshot-1 | [Symbol(connect-options)]: [Object],
matrix-hookshot-1 | [Symbol(RequestTimeout)]: undefined
matrix-hookshot-1 | },
matrix-hookshot-1 | _header: 'GET /api/v4/ONLYGROUPNAME/issues/NaN HTTP/1.1\r\n' +
matrix-hookshot-1 | 'Accept: application/json, text/plain, */*\r\n' +
matrix-hookshot-1 | 'Authorization: Bearer REDACTED\r\n' +
matrix-hookshot-1 | 'User-Agent: matrix-hookshot/1.7.3 (+https://github.com/matrix-org/matrix-hookshot)\r\n' +
matrix-hookshot-1 | 'Host: MYGITLABINSTANCE\r\n' +
matrix-hookshot-1 | 'Connection: close\r\n' +
matrix-hookshot-1 | '\r\n',
matrix-hookshot-1 | _keepAliveTimeout: 0,
matrix-hookshot-1 | _onPendingData: [Function: nop],
matrix-hookshot-1 | agent: Agent {
matrix-hookshot-1 | _events: [Object: null prototype],
matrix-hookshot-1 | _eventsCount: 2,
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | defaultPort: 443,
matrix-hookshot-1 | protocol: 'https:',
matrix-hookshot-1 | options: [Object: null prototype],
matrix-hookshot-1 | requests: [Object: null prototype] {},
matrix-hookshot-1 | sockets: [Object: null prototype],
matrix-hookshot-1 | freeSockets: [Object: null prototype] {},
matrix-hookshot-1 | keepAliveMsecs: 1000,
matrix-hookshot-1 | keepAlive: false,
matrix-hookshot-1 | maxSockets: Infinity,
matrix-hookshot-1 | maxFreeSockets: 256,
matrix-hookshot-1 | scheduling: 'lifo',
matrix-hookshot-1 | maxTotalSockets: Infinity,
matrix-hookshot-1 | totalSocketCount: 1,
matrix-hookshot-1 | maxCachedSessions: 100,
matrix-hookshot-1 | _sessionCache: [Object],
matrix-hookshot-1 | [Symbol(kCapture)]: false
matrix-hookshot-1 | },
matrix-hookshot-1 | socketPath: undefined,
matrix-hookshot-1 | method: 'GET',
matrix-hookshot-1 | maxHeaderSize: undefined,
matrix-hookshot-1 | insecureHTTPParser: undefined,
matrix-hookshot-1 | path: '/api/v4/ONLYGROUPNAME/NaN',
matrix-hookshot-1 | _ended: true,
matrix-hookshot-1 | res: IncomingMessage {
matrix-hookshot-1 | _readableState: [ReadableState],
matrix-hookshot-1 | _events: [Object: null prototype],
matrix-hookshot-1 | _eventsCount: 3,
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | socket: [TLSSocket],
matrix-hookshot-1 | httpVersionMajor: 1,
matrix-hookshot-1 | httpVersionMinor: 1,
matrix-hookshot-1 | httpVersion: '1.1',
matrix-hookshot-1 | complete: true,
matrix-hookshot-1 | rawHeaders: [Array],
matrix-hookshot-1 | rawTrailers: [],
matrix-hookshot-1 | aborted: false,
matrix-hookshot-1 | upgrade: false,
matrix-hookshot-1 | url: '',
matrix-hookshot-1 | method: null,
matrix-hookshot-1 | statusCode: 400,
matrix-hookshot-1 | statusMessage: 'Bad Request',
matrix-hookshot-1 | client: [TLSSocket],
matrix-hookshot-1 | _consuming: false,
matrix-hookshot-1 | _dumped: false,
matrix-hookshot-1 | req: [Circular *1],
matrix-hookshot-1 | responseUrl: 'https://MYGITLABINSTANCE/api/v4/ONLYGROUPNAME/issues/NaN',
matrix-hookshot-1 | redirects: [],
matrix-hookshot-1 | [Symbol(kCapture)]: false,
matrix-hookshot-1 | [Symbol(kHeaders)]: [Object],
matrix-hookshot-1 | [Symbol(kHeadersCount)]: 24,
matrix-hookshot-1 | [Symbol(kTrailers)]: null,
matrix-hookshot-1 | [Symbol(kTrailersCount)]: 0,
matrix-hookshot-1 | [Symbol(RequestTimeout)]: undefined
matrix-hookshot-1 | },
matrix-hookshot-1 | aborted: false,
matrix-hookshot-1 | timeoutCb: null,
matrix-hookshot-1 | upgradeOrConnect: false,
matrix-hookshot-1 | parser: null,
matrix-hookshot-1 | maxHeadersCount: null,
matrix-hookshot-1 | reusedSocket: false,
matrix-hookshot-1 | host: 'MYGITLABINSTANCE',
matrix-hookshot-1 | protocol: 'https:',
matrix-hookshot-1 | _redirectable: Writable {
matrix-hookshot-1 | _writableState: [WritableState],
matrix-hookshot-1 | _events: [Object: null prototype],
matrix-hookshot-1 | _eventsCount: 2,
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | _options: [Object],
matrix-hookshot-1 | _ended: true,
matrix-hookshot-1 | _ending: true,
matrix-hookshot-1 | _redirectCount: 0,
matrix-hookshot-1 | _redirects: [],
matrix-hookshot-1 | _requestBodyLength: 0,
matrix-hookshot-1 | _requestBodyBuffers: [],
matrix-hookshot-1 | _onNativeResponse: [Function (anonymous)],
matrix-hookshot-1 | _currentRequest: [Circular *1],
matrix-hookshot-1 | _currentUrl: 'https://MYGITLABINSTANCE/api/v4/ONLYGROUPNAME/issues/NaN',
matrix-hookshot-1 | [Symbol(kCapture)]: false
matrix-hookshot-1 | },
matrix-hookshot-1 | [Symbol(kCapture)]: false,
matrix-hookshot-1 | [Symbol(kNeedDrain)]: false,
matrix-hookshot-1 | [Symbol(corked)]: 0,
matrix-hookshot-1 | [Symbol(kOutHeaders)]: [Object: null prototype] {
matrix-hookshot-1 | accept: [Array],
matrix-hookshot-1 | authorization: [Array],
matrix-hookshot-1 | 'user-agent': [Array],
matrix-hookshot-1 | host: [Array]
matrix-hookshot-1 | }
matrix-hookshot-1 | },
matrix-hookshot-1 | response: {
matrix-hookshot-1 | status: 400,
matrix-hookshot-1 | statusText: 'Bad Request',
matrix-hookshot-1 | headers: {
matrix-hookshot-1 | 'cache-control': 'no-cache',
matrix-hookshot-1 | 'content-length': '32',
matrix-hookshot-1 | 'content-type': 'application/json',
matrix-hookshot-1 | date: 'Sun, 03 Jul 2022 11:18:19 GMT',
matrix-hookshot-1 | server: 'nginx',
matrix-hookshot-1 | 'strict-transport-security': 'max-age=15552000',
matrix-hookshot-1 | vary: 'Origin',
matrix-hookshot-1 | 'x-content-type-options': 'nosniff',
matrix-hookshot-1 | 'x-frame-options': 'SAMEORIGIN',
matrix-hookshot-1 | 'x-request-id': '01G71WGSR4C7S5VCCSQYJJA8N7',
matrix-hookshot-1 | 'x-runtime': '0.008226',
matrix-hookshot-1 | connection: 'close'
matrix-hookshot-1 | },
matrix-hookshot-1 | config: {
matrix-hookshot-1 | transitional: [Object],
matrix-hookshot-1 | adapter: [Function: httpAdapter],
matrix-hookshot-1 | transformRequest: [Array],
matrix-hookshot-1 | transformResponse: [Array],
matrix-hookshot-1 | timeout: 0,
matrix-hookshot-1 | xsrfCookieName: 'XSRF-TOKEN',
matrix-hookshot-1 | xsrfHeaderName: 'X-XSRF-TOKEN',
matrix-hookshot-1 | maxContentLength: -1,
matrix-hookshot-1 | maxBodyLength: -1,
matrix-hookshot-1 | validateStatus: [Function: validateStatus],
matrix-hookshot-1 | headers: [Object],
matrix-hookshot-1 | baseURL: 'https://MYGITLABINSTANCE',
matrix-hookshot-1 | method: 'get',
matrix-hookshot-1 | url: 'api/v4/projects/ONLYGROUPNAME/NaN',
matrix-hookshot-1 | data: undefined
matrix-hookshot-1 | },
matrix-hookshot-1 | request: ClientRequest {
matrix-hookshot-1 | _events: [Object: null prototype],
matrix-hookshot-1 | _eventsCount: 7,
matrix-hookshot-1 | _maxListeners: undefined,
matrix-hookshot-1 | outputData: [],
matrix-hookshot-1 | outputSize: 0,
matrix-hookshot-1 | writable: true,
matrix-hookshot-1 | destroyed: false,
matrix-hookshot-1 | _last: true,
matrix-hookshot-1 | chunkedEncoding: false,
matrix-hookshot-1 | shouldKeepAlive: false,
matrix-hookshot-1 | maxRequestsOnConnectionReached: false,
matrix-hookshot-1 | _defaultKeepAlive: true,
matrix-hookshot-1 | useChunkedEncodingByDefault: false,
matrix-hookshot-1 | sendDate: false,
matrix-hookshot-1 | _removedConnection: false,
matrix-hookshot-1 | _removedContLen: false,
matrix-hookshot-1 | _removedTE: false,
matrix-hookshot-1 | _contentLength: 0,
matrix-hookshot-1 | _hasBody: true,
matrix-hookshot-1 | _trailer: '',
matrix-hookshot-1 | finished: true,
matrix-hookshot-1 | _headerSent: true,
matrix-hookshot-1 | _closed: false,
matrix-hookshot-1 | socket: [TLSSocket],
matrix-hookshot-1 | _header: 'GET /api/v4/projects/ONLYGROUPNAME/issues/NaN HTTP/1.1\r\n' +
matrix-hookshot-1 | 'Accept: application/json, text/plain, */*\r\n' +
matrix-hookshot-1 | 'Authorization: Bearer REDACTED\r\n' +
matrix-hookshot-1 | 'User-Agent: matrix-hookshot/1.7.3 (+https://github.com/matrix-org/matrix-hookshot)\r\n' +
matrix-hookshot-1 | 'Host: MYGITLABINSTANCE\r\n' +
matrix-hookshot-1 | 'Connection: close\r\n' +
matrix-hookshot-1 | '\r\n',
matrix-hookshot-1 | _keepAliveTimeout: 0,
matrix-hookshot-1 | _onPendingData: [Function: nop],
matrix-hookshot-1 | agent: [Agent],
matrix-hookshot-1 | socketPath: undefined,
matrix-hookshot-1 | method: 'GET',
matrix-hookshot-1 | maxHeaderSize: undefined,
matrix-hookshot-1 | insecureHTTPParser: undefined,
matrix-hookshot-1 | path: '/api/v4/projects/ONLYGROUPNAME/issues/NaN',
matrix-hookshot-1 | _ended: true,
matrix-hookshot-1 | res: [IncomingMessage],
matrix-hookshot-1 | aborted: false,
matrix-hookshot-1 | timeoutCb: null,
matrix-hookshot-1 | upgradeOrConnect: false,
matrix-hookshot-1 | parser: null,
matrix-hookshot-1 | maxHeadersCount: null,
matrix-hookshot-1 | reusedSocket: false,
matrix-hookshot-1 | host: 'MYGITLABINSTANCE',
matrix-hookshot-1 | protocol: 'https:',
matrix-hookshot-1 | _redirectable: [Writable],
matrix-hookshot-1 | [Symbol(kCapture)]: false,
matrix-hookshot-1 | [Symbol(kNeedDrain)]: false,
matrix-hookshot-1 | [Symbol(corked)]: 0,
matrix-hookshot-1 | [Symbol(kOutHeaders)]: [Object: null prototype]
matrix-hookshot-1 | },
matrix-hookshot-1 | data: { error: 'issue_iid is invalid' }
matrix-hookshot-1 | },
matrix-hookshot-1 | isAxiosError: true,
matrix-hookshot-1 | toJSON: [Function: toJSON]
matrix-hookshot-1 | }
```

**To Reproduce**

1. Set a token for a GitLab instance with Hookshot.
2. Send `gitlab open issue PROJECT`

**Expected behavior**
An issue room is created.

I'm running the latest Docker image, with this config:

```
gitlab:
instances:
ALIAS:
url: GITURL
webhook:
secret: SECRET
publicUrl: WEBHOOKURL
userIdPrefix: _gitlab_
```

From looking at the logged error, hookshot tries to get an issue via the API by the name of "NaN", which fails for obvious reasons. Also, instead of looking for calling the API with the full project path, it only seems to use the group, so the URLs logged are e.g. /api/v4/projects/ONLYGROUPNAME/issues/NaN instead of /api/v4/projects/GROUPNAME/PROJECTNAME/issues/1 which would expect.

Contributor guide

Open the contributing guide

Research direction

Start at the handler for the `gitlab open issue` command and follow the `AdminRoom` and `GitLabClient` flow shown in the logs. Reproduce the command with a personal GitLab token and trace why the issue IID becomes `NaN`; done means the command performs a valid GitLab issue lookup and creates the issue room instead of returning an undefined error.

Written by the indexing model from the issue text.

Assessment

Tech stack
gitlab, typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.