Giter Site home page Giter Site logo

adapter-aws-lambda-serverless's Introduction

Probot's logo, a cartoon robot

A framework for building GitHub Apps to automate and improve your workflow

npm Build Status Codecov @ProbotTheRobot on Twitter


If you've ever thought, "wouldn't it be cool if GitHub couldโ€ฆ"; I'm going to stop you right there. Most features can actually be added via GitHub Apps, which extend GitHub and can be installed directly on organizations and user accounts and granted access to specific repositories. They come with granular permissions and built-in webhooks. Apps are first class actors within GitHub.

How it works

Probot is a framework for building GitHub Apps in Node.js, written in TypeScript. GitHub Apps can listen to webhook events sent by a repository or organization. Probot uses its internal event emitter to perform actions based on those events. A simple Probot App might look like this:

export default (app) => {
  app.on("issues.opened", async (context) => {
    const issueComment = context.issue({
      body: "Thanks for opening this issue!",
    });
    return context.octokit.issues.createComment(issueComment);
  });

  app.onAny(async (context) => {
    context.log.info({ event: context.name, action: context.payload.action });
  });

  app.onError(async (error) => {
    app.log.error(error);
  });
};

Building a Probot App

If you've landed in this GitHub repository and are looking to start building your own Probot App, look no further than probot.github.io! The Probot website contains our extensive getting started documentation and will guide you through the set up process.

This repository hosts the code for the npm Probot package which is what all Probot Apps run on. Most folks who land in this repository are likely looking to get started building their own app.

Contributing

Probot is built by people just like you! Most of the interesting things are built with Probot, so consider starting by writing a new app or improving one of the existing ones.

If you're interested in contributing to Probot itself, check out our contributing docs to get started.

Want to discuss with Probot users and contributors? Discuss on GitHub!

Ideas

Have an idea for a cool new GitHub App (built with Probot)? That's great! If you want feedback, help, or just to share it with the world you can do so by creating an issue in the probot/ideas repository!

adapter-aws-lambda-serverless's People

Contributors

ajschmidt8 avatar axel3rd avatar danny-waite avatar davidjfelix avatar decompil3d avatar dependabot[bot] avatar gr2m avatar itaditya avatar jakebolam avatar jasonetco avatar jaylenw avatar kylerjensen avatar mattcan avatar mattkinnersley avatar mrchief avatar nimrodolev avatar oatelaus avatar oscard0m avatar renovate[bot] avatar scolandrea avatar swain avatar tcbyrd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

adapter-aws-lambda-serverless's Issues

Missing 'issuer' claim ('iss') in assertion

I am seeing the error in CloudWatch Logs when trying to invoke a Lambda function from our API Gateway Endpoint. I found out it's because it's not correctly picking up the APP_ID value from the .env file correctly.

I was able to workaround the issue by specifying the APP_ID environment variable through the environment variables set in Lambda.

"errorMessage": "Cannot convert undefined or null to object",

{
"errorType": "TypeError",
"errorMessage": "Cannot convert undefined or null to object",
"trace": [
"TypeError: Cannot convert undefined or null to object",
" at Function.entries ()",
" at module.exports (/var/task/node_modules/lowercase-keys/index.js:5:36)",
" at lambdaFunction (/var/task/node_modules/@probot/adapter-aws-lambda-serverless/lambda-function.js:19:28)",
" at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)"
]
}

My probot lambda function is having issue above.

Upgrade to Probot v10

Hello Lambda friends,

we just released Probot v10 and I'd like to upgrade @probot/serverless-lambda for compatibility. Would any existing user/contributor would like to collaborate on that with me?

More importantly, I'd like to make this package obsolete with Probot v11. I'm not sure how it would look like, but making Probot play nicely with serverless environments is our priority for the next release. Please join the discussion at
probot/probot#1286

When to expect a release that supports Probot v12?

Background Info

I have a Probot application running Probot major version 11.4.1 that depends on this AWS Lambda Serverless adapter. I upgraded this adapter to v2.1.0 in my Probot application. I also understand that the v2.1.0 release had type definitions added seen here which is excellent. I then proceeded to upgrade my Probot application to the latest release version which is v12.1.1.

Problem

I am now unable to build my Probot application with TypeScript as I understand that the current latest release of this adapter does not support Probot v12. You can see below that I am encountering a type mismatch:

src/handler.ts(12,48): error TS2345: Argument of type '(app: Probot) => void' is not assignable to parameter of type 'ApplicationFunction'.
  Types of parameters 'app' and 'app' are incompatible.
    Type 'import("/home/user/WorkSpace/GitHub/myapp/node_modules/@probot/adapter-aws-lambda-serverless/node_modules/probot/lib/probot").Probot' is not assignable to type 'import("/home/user/WorkSpace/GitHub/myapp/node_modules/probot/lib/probot").Probot'.
      The types returned by 'webhooks.sign(...)' are incompatible between these types.
        Type 'string' is not assignable to type 'Promise<string>'.

Please note I am using almost the exact same code that is currently on the README that should be in handler.js / handler.ts.

The key string to notice is Type 'string' is not assignable to type 'Promise<string>'. This is the result to the changes made to Probot v12, if I understood correctly, the octokit webhooks has been changed (see here for the diff with some test cases reflecting this relating to "x-hub-signature": sign("secret", body), and "x-hub-signature-256": await sign("secret", body),.

Question

Long story short, when may we expect a new major version for this adapter to support Probot v12? I am thinking at minimum the Probot version in the package.json file will need to be set to v12 and that should update the type definitions.

I thank all of the contributors for their hard work on the project! ๐Ÿ‘๐Ÿฝ

Allow custom log function to be provided

Currently this library logs using console methods.

We're using structured logging in JSON using a library (Pino but that's not relevant here) in all of our applications, including AWS Lambda functions. Using this library currently results in unstructured log statements in our log aggregation which makes queries difficult.

I'd suggest adding a logger parameter to an options object and then calling that instead of console, defaulting to console if none is provided.

e.g.

serverless(handler, {logger});

where logger has the same interface as console.

getRouter is `undefined`

I'm trying to add HTTP routes to a Probot app deployed to AWS Lambda with your adapter. The HTTP route /api/hello-world added works when deploying the app locally with nodemon src/index.ts. However, the endpoint returns the error 500 when deployed to AWS Lambda with Serverless because getRouter is undefined.

2022-10-16T19:17:01.251Z	undefined	ERROR	Unhandled Promise Rejection 	
{
    "errorType": "Runtime.UnhandledPromiseRejection",
    "errorMessage": "Error: getRouter is undefined",
    "reason": {
        "errorType": "Error",
        "errorMessage": "getRouter is undefined",
        "stack": [
            "Error: getRouter is undefined",
            "    at /var/task/src/index.js:9:15",
            "    at Generator.next (<anonymous>)",
            "    at /var/task/node_modules/tslib/tslib.js:118:75",
            "    at new Promise (<anonymous>)",
            "    at Object.__awaiter (/var/task/node_modules/tslib/tslib.js:114:16)",
            "    at challengeBot (/var/task/src/index.js:7:54)",
            "    at Probot.load (/var/task/node_modules/probot/lib/probot.js:80:16)",
            "    at createLambdaFunction (/var/task/node_modules/@probot/adapter-aws-lambda-serverless/index.js:14:10)",
            "    at Object.<anonymous> (/var/task/src/lambda/handler.js:5:84)",
            "    at Module._compile (node:internal/modules/cjs/loader:1105:14)"
        ]
    },
    "promise": {},
    "stack": [
        "Runtime.UnhandledPromiseRejection: Error: getRouter is undefined",
        "    at process.<anonymous> (file:///var/runtime/index.mjs:1131:17)",
        "    at process.emit (node:events:527:28)",
        "    at process.emit (node:domain:475:12)",
        "    at emit (node:internal/process/promises:140:20)",
        "    at processPromiseRejections (node:internal/process/promises:274:27)",
        "    at processTicksAndRejections (node:internal/process/task_queues:97:32)"
    ]
}

Is this behavior to be expected when using this adatper and deploying on AWS lambda? Probot doc mentions that getRouter will be set only when running the app with probot run or using their Server.

src/index.ts:

import { ApplicationFunctionOptions, Probot, run } from 'probot';
import * as express from 'express';

export const challengeBot = async (
  app: Probot,
  { getRouter }: ApplicationFunctionOptions
): Promise<void> => {
  if (!getRouter) {
    throw new Error('getRouter is undefined');
  }

  const router = getRouter('/api');
  router.use(express.json());
  router.get('/hello-world', (req, res) => {
    res.json({ a: 1 });
  });

  app.on('issues.opened', async (context) => {
    const issueComment = context.issue({
      body: 'Thanks for opening this issue!',
    });
    await context.octokit.issues.createComment(issueComment);
  });
};

run(challengeBot);

Module resolution problems with TypeScript

I'm unable to import this when transpiling/compiling with TypeScript.
If I copy the functionality from the module directly into my handler function, it works as expected.

I've tried various different module resolution & target module systems, as well as aliasing and directly addressing. Surely I've just misconfigured something?

I have a PoC/sample config below.

// handler.ts
/**
* @param {import('probot').Application} app
* @param {import('probot').Context} context
*/

const { createProbot } = require('probot')
const { resolve } = require('probot/lib/resolver')
const { findPrivateKey } = require('probot/lib/private-key')
// const { template } = require('./views/probot')

let probot

const loadProbot = appFn => {
  probot = probot || createProbot({
    id: process.env.APP_ID,
    secret: process.env.WEBHOOK_SECRET,
    cert: findPrivateKey()
  })

  if (typeof appFn === 'string') {
    appFn = resolve(appFn)
  }

  probot.load(appFn)

  return probot
}

const serverless = appFn => {
  return async (event, context) => {
    // ๐Ÿค– A friendly homepage if there isn't a payload
    if (event.httpMethod === 'GET' && event.path === '/probot') {
      const res = {
        statusCode: 200,
        headers: {
          'Content-Type': 'text/html'
        },
        body: 'replaced template with string'
      }
      return context.done(null, res)
    }

    // Otherwise let's listen handle the payload
    probot = probot || loadProbot(appFn)

    // Ends function immediately after callback
    context.callbackWaitsForEmptyEventLoop = false

    // Determine incoming webhook event type
    const e = event.headers['x-github-event'] || event.headers['X-GitHub-Event']

    // Convert the payload to an Object if API Gateway stringifies it
    event.body = (typeof event.body === 'string') ? JSON.parse(event.body) : event.body

    // Do the thing
    console.log(`Received event ${e}${event.body.action ? ('.' + event.body.action) : ''}`)
    if (event) {
      try {
        await probot.receive({
          name: e,
          payload: event.body
        })
        const res = {
          statusCode: 200,
          body: JSON.stringify({
            message: `Received ${e}.${event.body.action}`
          })
        }
        return context.done(null, res)
      } catch (err) {
        console.error(err)
        return context.done(null, {
          statusCode: 500,
          body: JSON.stringify(err)
        })
      }
    } else {
      console.error({ event, context })
      context.done(null, 'unknown error')
    }
    return context.done(null, {
      statusCode: 200,
      body: 'Nothing to do.'
    })
  }
}

// const { serverless } = require('@probot/serverless-lambda')
// import { serverless } from '@probot/serverless-lambda/index'
// import * as serverless from '@probot/serverless-lambda';
// import { serverless } from 'serverless-lambda'

const pro = (app) => {
  app.log('Yay, the app was loaded!')

  app.on('issues.opened', async context => {
    const issueComment = context.issue({ body: 'Thanks for opening this issue!' })
    return context.github.issues.createComment(issueComment)
  })
}

module.exports.pro = serverless(pro)
// tsconfig.json
{
  "compilerOptions": {
    "allowJs": false,
    "lib": ["es2015", "es2017"],
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es6",
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": false,
    "pretty": true,
    "strict": true,
    "sourceMap": true,
    "outDir": "./lib",
    "skipLibCheck": true,
    "noImplicitAny": false, // Disabled
    "esModuleInterop": true,
    "declaration": true,
    "resolveJsonModule": true
  },
  "include": [
    "src/**/*"
  ],
  "compileOnSave": false
}

Pass GithubToken as option when building probot serverless app

https://github.com/probot/serverless-lambda/blob/a4688897217d206f0397d81dc4b457123fc302b9/index.js#L8-L13

Problem:

Right now is not possible to create a serverless probot app with a githubToken as option so we obtain an authenticated Github App installation.

Context:

Trying to create a serverless probot authenticated with Github App Installation but not possible on creation with the constructor parameters offered right now.

A workaround is a wrapper appFn used as callback for the .on() where we do the authentication:

	withWebHookContext(app: Application, next: Function): (ctx: Context) => Promise<void> {
		return async(context: Context): Promise<void> => {
			let webhookContext = context as WebhookContext;
                         
                          const github = await app.auth();

		        const { data } = await github.apps.createInstallationToken({
			     installation_id: context.payload.installation.id
		        });

		       webhookContext.gitHubToken = data.token;

		       await next(webhookContext);
		};
	}
app.on(PUSH, decorator.withWebHookContext(app,
		mergeHandler.handle.bind(mergeHandler)));

Solution proposal:

To support process.env.GITHUB_TOKEN environment variable and call createProbot(Options) with githubToken in the Options

  • If there is an agreement on the issue and proposal solution I will be happy to draft a PR on it.

AWS Gateway : OpenAPI v3 YAML sample for deployment

In part of #61, I tried to add an OpenAPI v3 AWS Gateway REST API deployment (aka: Manual AWS Lambda + API deployment).

The most simple looks file:

openapi: "3.0.1"
info:
  title: "my-probot"
  description: "API endpoint for my Probot hosted on Lambda"
  version: "1.0"
paths:
  /api/github/webhooks:
    post:
      x-amazon-apigateway-integration:
        type: "aws_proxy"
        httpMethod: "POST"
        # URI of Lambda (should end by /invocations)
        # Replace: xxx-region-xxx (x2), xxx-account-xxx, xxx-lambda-name-xxx
        # The ARN (the suffix of URI) can be retrieved from top right of your Lambda AWS console)
        uri: "arn:aws:apigateway:xxx-region-xxx:lambda:path/2015-03-31/functions/arn:aws:lambda:xxx-region-xxx:xxx-account-xxx:function:xxx-lambda-name-xxx/invocations"

Unfortunately, in the case, the Resource Policies of lambda is not updated to authorize API invocation (Lambda > Permission tab : Resource-based policy).

Should be like:

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "probot-name-api-permission",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:xxx-region-xxx:xxx-account-xxx:function:xxx-lambda-name-xxx",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:xxx-region-xxx:xxx-account-xxx:xxx-api-id-xxx/*/*/api/github/webhooks"
        }
      }
    }
  ]
}

No found a way to add it manually, require AWS Cli or SDK => perhaps using Serverless Framework is more sustainable.

TypeError: Cannot read property 'wrap' of undefined

Issue

I am testing out the serverless-lambda plugin using what is currently on npm:

npm i @probot/serverless-lambda

It seems to fail when trying to connect to probot and auth

Error

ERROR event: Cannot read property 'wrap' of undefined
  TypeError: Cannot read property 'wrap' of undefined
      at Application.<anonymous> (/var/task/node_modules/probot/lib/application.js:253:57)
      at step (/var/task/node_modules/probot/lib/application.js:40:23)
      at Object.next (/var/task/node_modules/probot/lib/application.js:21:53)
      at /var/task/node_modules/probot/lib/application.js:15:71
      at new Promise (<anonymous>)
      at __awaiter (/var/task/node_modules/probot/lib/application.js:11:12)
      at Application.auth (/var/task/node_modules/probot/lib/application.js:237:16)
      at Application.<anonymous> (/var/task/node_modules/probot/lib/application.js:183:59)
      at step (/var/task/node_modules/probot/lib/application.js:40:23)
      at Object.next (/var/task/node_modules/probot/lib/application.js:21:53)
      at /var/task/node_modules/probot/lib/application.js:15:71
      at new Promise (<anonymous>)
      at __awaiter (/var/task/node_modules/probot/lib/application.js:11:12)
      at EventEmitter.<anonymous> (/var/task/node_modules/probot/lib/application.js:167:72)
      at Promise.all.handlers.map.handler (/var/task/node_modules/promise-events/emitter.js:125:28)
      at Array.map (<anonymous>)
      at EventEmitter.emit (/var/task/node_modules/promise-events/emitter.js:123:40)
      at Application.<anonymous> (/var/task/node_modules/probot/lib/application.js:100:37)
      at step (/var/task/node_modules/probot/lib/application.js:40:23)
      at Object.next (/var/task/node_modules/probot/lib/application.js:21:53)
      at /var/task/node_modules/probot/lib/application.js:15:71
      at new Promise (<anonymous>)
      at __awaiter (/var/task/node_modules/probot/lib/application.js:11:12)
      at Application.receive (/var/task/node_modules/probot/lib/application.js:90:16)
      at /var/task/node_modules/@probot/serverless-lambda/index.js:57:19
  --
  event: {
    "event": "issues.opened",
    "installation": 348774,
    "repository": "bdougie/bot-test-repo"
  }

I am currently catching an error from app.receive. It seems like it is trying to call wrap on this.cache. I discovered this while digging through the compiled JavaScript file in the installed node_module.

My attempt at a fix

I took at look the uncompiled TypeScript file where the error is coming from is here: https://github.com/probot/probot/blob/782707af676721e8722dc39dc53b6a89b7032171/src/application.ts#L216.

// node_modules/probot/lib/application.js

var Application = /** @class */ (function () {
    function Application(options) {
        var opts = options || {};
        this.cache = opts.cache;
       ...
    }

...

  Application.prototype.auth = function (id, log) {
        if (log === void 0) { log = this.log; }
        return __awaiter(this, void 0, void 0, function () {
            var github, installationTokenTTL, res;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (process.env.GHE_HOST && /^https?:\/\//.test(process.env.GHE_HOST)) {
                            throw new Error('Your \`GHE_HOST\` environment variable should not begin with https:// or http://');
                        }
                        github = github_1.GitHubAPI({
                            baseUrl: process.env.GHE_HOST && "https://" + process.env.GHE_HOST + "/api/v3",
                            debug: process.env.LOG_LEVEL === 'trace',
                            logger: log.child({ name: 'github', installation: String(id) })
                        });
                        installationTokenTTL = parseInt(process.env.INSTALLATION_TOKEN_TTL || '3540', 10);
                        if (!id) return [3 /*break*/, 2];
  ERROR HAPPENS HERE   ----->           return [4 /*yield*/, this.cache.wrap("app:" + id + ":token", function () {
                                log.trace("creating token for installation");
                                github.authenticate({ type: 'app', token: _this.app() });
                                return github.apps.createInstallationToken({ installation_id: String(id) });
                            }, { ttl: installationTokenTTL })];
                    case 1:
                        res = _a.sent();
                        github.authenticate({ type: 'token', token: res.data.token });
                        return [3 /*break*/, 3];
                    case 2:
                        github.authenticate({ type: 'app', token: this.app() });
                        _a.label = 3;
                    case 3: return [2 /*return*/, github];
                }
            });
        });
    };
    return Application;

This is my first time working with TypeScript and digging into the Probot source, not entirley what is exactly going on.

I did attempt to manually pass options, but it still seems like the Cache is still undefined.

    await app.receive({
          name: e,
          payload: event.body,
       +  options: {ttl: 100}
     })

Help

Curious if anyone can point me towards the solution and if I am at all close to thinking this this.cache is the issue. Even an explanation on how the Cache is being leveraged in Probot would help. ๐Ÿ™๐Ÿพ

// node_modules/probot/lib/application.d.ts

export declare class Application {
    cache: Cache;
  ...
}
...
export interface Cache {
    wrap<T>(key: string, wrapper: (callback: (error: any, result: T) => void) => any, options: CacheConfig): Promise<any>;
}

cc/ @tcbyrd

Provide GitHub Authentication variables programatically

Is there any plan to support providing GitHub credential information (APP_ID, WEBHOOK_SECRET, PRIVATE_KEY) without environment variables?

For example, something like:

const { serverless } = require('@probot/serverless-lamda');

module.exports.probot = serverless({
  app: myAppFn,
  getAuthentication: () => {
     // retrieve values, and return e.g.
    return { appId, privateKey, webhookSecret };
  }
})

Thanks!

Unable to run the lambda asynchronously

I am having the app.js code like below. While invoking the lambda asynchronously, it's not waiting for any event emitter callback to execute.

module.exports = async (app) => {
  // Your code here
  app.log.info("Yay, the app was loaded!");

  await new Promise(resolve => {
    app.log.info('waiting for event....')
    app.on("issues.opened", async (context) => {
      const issueComment = context.issue({
        body: "Thanks for opening this issue!",
      });
      resolve(context.octokit.issues.createComment(issueComment));
    });

    app.on("deployment_status.created", async (context) => {

      let deployment_status = context.payload.deployment_status.state
      app.log.info(`deployment_status created: ${deployment_status}`)
      const config = await context.config('config.yaml');

      if (deployment_status == 'success') {
        app.log.info(context.repo().repo)
        app.log.info(`Deployment - exclude environement ${config.deployment.environment.excludes}`)
        app.log.info(sign(context.payload, "development"))
        resolve()
      }
    });

  })
  app.log.info('Exiting ....')
};

How do we implement this?

HI @tcbyrd,

Thanks for putting this together. We've been trying to get a simple probot app (that performs a check on pull request description) working on lambda. We got it working locally with smee but we're at a dead end on how to deploy it to lambda.
We've setup a new API in API Gateway and were able to test sending a payload to the lambda function. The issue is that the event handler defined in our app's index.js doesn't process the event and instead it gets processed by serverless-lambda (returns "Hello Node8!").

Could you provide a bit more information on how to get it working?

Thanks,

Incompatible with Probot v11

Got this error with probot 11.0.1 and 11.0.5. Downgrading to 10.19.0 solved it.

HttpError: Missing 'issuer' claim ('iss') in assertion
at /var/task/node_modules/@octokit/request/dist-node/index.js:66:23
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async getInstallationAuthentication (/var/task/node_modules/@octokit/auth-app/dist-node/index.js:258:7)
at async hook (/var/task/node_modules/@octokit/auth-app/dist-node/index.js:424:7)
at async Job.doExecute (/var/task/node_modules/bottleneck/light.js:405:18)

TypeError: Cannot read property 'action' of undefined

The code at https://github.com/probot/serverless-lambda/blob/master/index.js#L51 doesn't account for cases where event.body could be absent (e.g. using custom routes).

I think a check for event.body.action would at least avoid this error.

A better fix would be to account for other routes and invoke next() instead of trying to handle it within probot.

Stack trace
  at <path/to/repo>\node_modules\@probot\serverless-lambda\index.js:51:50
    at nameSpace.run (<path/to/repo>\node_modules\node-lambda\lib\main.js:125:22)
    at Namespace.run (<path/to/repo>\node_modules\continuation-local-storage\context.js:48:5)
    at Lambda._runHandler (<path/to/repo>\node_modules\node-lambda\lib\main.js:123:15)
    at Lambda.run (<path/to/repo>\node_modules\node-lambda\lib\main.js:84:10)
    at Command.program.command.alias.description.option.option.option.option.option.option.option.option.action (<path/to/repo>\node_modules\node-lambda\bin\node-lambda:138:27)
    at Command.listener (<path/to/repo>\node_modules\commander\index.js:315:8)
    at emitTwo (events.js:126:13)
    at Command.emit (events.js:214:7)
    at Command.parseArgs (<path/to/repo>\node_modules\commander\index.js:654:12)
    at Command.parse (<path/to/repo>\node_modules\commander\index.js:474:21)
    at Object.<anonymous> (<path/to/repo>\node_modules\node-lambda\bin\node-lambda:149:4)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Headers case-insensitivity

id:
event.headers["X-GitHub-Delivery"] ||
event.headers["x-github-delivery"],
name: event.headers["X-GitHub-Event"] || event.headers["x-github-event"],

From RFC 7230 > 3.2. Header Fields:

Each header field consists of a case-insensitive field name followed by a colon (":"), optional leading whitespace, the field value, and optional trailing whitespace.

=> If you are testing (sample #61) your Lambda Probot with some tools which can "rewrite" headers (sample: Ansible URI module) like that (in Camel Case):

X-Github-Delivery: fake-ansible
X-Github-Event: test

Note the 'h' in lowercase

It doesn't work ๐Ÿ˜ข. It would be nice if adapter-aws-lambda-serverless could be headers case-insensitive.

Error detail:

INFO	AggregateError: 
    Error: Event name not passed
        at Array.map (<anonymous>)
        at receiverHandle (/var/task/node_modules/@octokit/webhooks/dist-node/index.js:98:11)
        at verifyAndReceive (/var/task/node_modules/@octokit/webhooks/dist-node/index.js:307:29)
        at lambdaFunction (/var/task/node_modules/@probot/adapter-aws-lambda-serverless/lambda-function.js:12:24)
        at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
    at receiverHandle (/var/task/node_modules/@octokit/webhooks/dist-node/index.js:98:11)
    at verifyAndReceive (/var/task/node_modules/@octokit/webhooks/dist-node/index.js:307:29)
    at lambdaFunction (/var/task/node_modules/@probot/adapter-aws-lambda-serverless/lambda-function.js:12:24)
    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)

NB: False line number, console.log added for debug

Issue with serverless config for running probot on lambda

I am successfully running the standard sample create-probot-app locally and have integrated it with a github repo. Using this extension, I am trying to put this on lambda, but I continuously see this error message with multiple configuration tries.

{
"errorType": "TypeError",
"errorMessage": "Cannot convert undefined or null to object",
"trace": [
"TypeError: Cannot convert undefined or null to object",
" at Function.keys ()",
" at lowerCaseKeys (/var/task/node_modules/@probot/serverless-lambda/index.js:25:10)",
" at Runtime.handler (/var/task/node_modules/@probot/serverless-lambda/index.js:49:21)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}

My serverless.yml is:

service: serverless-my-first-app
provider:
name: aws
runtime: nodejs10.x

functions:
probot:
handler: handler.probot
events:
- http: ANY /
- http: 'ANY {proxy+}'

This is my handler.js

// handler.js
const { serverless } = require('@probot/serverless-lambda')
const appFn = require('./index.js')
module.exports.probot = serverless(appFn)

npm package 0.2.0 has old files

I was getting Error: Property eventis deprecated, usename`` but the code seems to use the newer property. After a lot of head scratching, I checked the distributed files in the package and found the discrepancy:

image

Incorrect handling of base64 encoded request body from ApiGatway integration

In short

When data from the body property of a request from ApiGatway is base64 encoded, it is not being read correctly and an exception is thrown.

More details

When using protobot/serverless-lambda inside an AWS lambda function via and AWS ApiGatway proxy integration, the request body may be sent to the function as a base64 encoded string. The event data contains a dedicated field, isBase64Encoded, meant to indicate this. This field is not being read, and so we make an attempt to parse the body as JSON without decoding it first, causing an exception to be thrown.

Quick workaround

Replacing the handler.js example suggested in the readme with something like this solves the issue -

const { serverless } = require('@probot/serverless-lambda')
const appFn = require('./')
var app = serverless(appFn)
module.exports.probot = function (request: any, context: any, callback: any) {
    if (request.isBase64Encoded) {
        request.body = Buffer.from(request.body, "base64").toString('utf8');
    }
    app(request, context, callback);
}

Receiving error response of "oops"

I'm building a probot app that when a user stars a repo, they either get invited to the repo or an issue is opened depending on specific situations. The probot app was working great when I tested via smee, but now that I've put this up on aws lambda I've run into issues.

Initially, I had followed directions from this guide: https://bdougie.github.io/sls-probot-guide/

I realized that part of my issue was the directions are using a deprecated npm package called @probot/serverless-lambda.

I followed the directions found in this repository, and I'm using @probot/adapter-aws-lambda-serverless instead, but when I hit my lambda function, I receive an error that's not very descriptive. It just says "oops".

See screenshot:
image

Here's my PR: https://github.com/maintainers/invite-automation/pull/33/files

https://github.com/maintainers/invite-automation: whole repo

For my GitHub app..I updated my url. Perhaps, I haven't done that part correctly?

probot/serverless-lambda is not in the npm registry

I get an error while installing @probot/serverless-lambda.

I run:

npm i @probot/serverless-lambda

I get the error:

16 verbose Windows_NT 10.0.19041
17 verbose argv "c:\\Program Files\\nodejs\\node.exe" "c:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "@probot/serverless-lambda"
18 verbose node v12.18.3
19 verbose npm  v6.14.6
20 error code E404
21 error 404 Not Found - GET https://registry.npmjs.org/@probot%2fserverless-lambda - Not found
22 error 404
23 error 404 '@probot/serverless-lambda@^0.5.0' is not in the npm registry.
24 error 404 You should bug the author to publish it (or use the name yourself!)
25 error 404 Note that you can also install from a
26 error 404 tarball, folder, http url, or git url. 

Could you please help ?

README improvments proposal

Following #58, README content is nice for a Probot v11 from scratch.

Here a draft (I will do a PR after acceptance/remarks) for (potentials) README improvments on 3 themes:

  1. Synthesis of server-less adapter changes for Probot prior v11 migration (it could be quite easy to forget an item when you are migrating from Probot <=v10)
  2. Lambda endpoint URL
  3. Smoke test with Probot v11 (Pain point for to propose a PR)

//1. This new part between 'Examples' and 'LICENSE'

Probot v11 migration key points

For Probot v11 support, this adapter introduces significant changes. Here the key points to update (in addition of Probot v11 breaking changes):

Key point / Probot <= v10 >= v11
NPM package name @probot/serverless-lambda @probot/adapter-aws-lambda-serverless
handler.js content See Usage v1.x See Usage
AWS Lambda Runtime handler.probot handler.webhooks
AWS Lambda Handler Node.js 12.x (preferred) Node.js 12.x (required)

//2. Lambda endpoint URL

Make sure to configure your GitHub App registration's webhook URL to <your lambda's URL>/api/github/webhooks

The /api/github/webhooks is quite disturbing ... from Probot v10 usage it is like we need to add this URL suffix (but no).

I propose to remove it and explain that the lambda's URL is the invoke URL for POST verb, which can be found in the Stages configuration from the Amazon API Gateway console.


//3. Smoke test with Probot v11

This adapter is amazing, the best way to deploy stateless Probot ๐Ÿ˜—.

But with the matrix AwsNodeRuntime + Probot version + Serverless adapter version, it is sometime hard to troubleshoot a problem, and end2end configuration with a GitHub is not the simplest.

Having the way todo a smoke test could be nice. With Probot v10, this one worked fine:

$ curl --request POST --header "X-Github-Event: test" --data "{\"action\": \"test\"}"  https://x.execute-api.y.amazonaws.com/github-probots/sample-probot
{"message":"Received test.test"}

With Probot v11, we should deal with X-Hub-Signature header ๐Ÿ˜ข (Thanks to Securing your webhooks ^^).

I would like provide a snippet like that, but I haven't succeeded at this time (is it achievable with openssl dgst ?) ... if anybody has some advices, many thanks !

$ LAMBDA_URL=https://x.execute-api.y.amazonaws.com/github-probots/sample-probot
$ TMP_DATA_FILE=/tmp/smoke.data
$
$ echo "{\"action\": \"test\"}" > $TMP_DATA_FILE
$ SIGN=$(openssl dgst -sha1 -hmac $HERE_THE_WEBHOOK_SECRET_??_OR_NOT $TMP_DATA_FILE | cut -d" " -f2)
$ curl --request POST --header "X-Hub-Signature: sha1=$SIGN" --header "X-Github-Event: test" --data-binary "@$TMP_DATA_FILE" $LAMBDA_URL
{"message":"Received test.test"}

Fails in case of AWS Lambda cold start

I have used this extension to deploy my Probot on Lambda, my use case is I want to trigger the build on Travis CI when I add a comment on Pull Request. My issue is when I add a comment on a PR for the first time or after a while like 1 hour, it doesn't trigger the build and when the lambda resources are available or after the first failed try it triggers the build successfully.

Its my first issue, so be cool if I haven't provided sufficient details

Log AWS and Custom Fields to AWS CloudWatch Log

I'm creating a Probot app using the sample code, like so:

const {
    createLambdaFunction,
    createProbot,
} = require("@probot/adapter-aws-lambda-serverless");
const appFn = require("./");

exports.handler = createLambdaFunction(appFn, {
    probot: createProbot(),
});

My NODE_ENV is set to production, which sets the pino logging output to JSON, which is logged to AWS CloudWatch.

Update: The environment variable is set, but the logging is not JSON; it's still pretty print.

However, the logs are missing some key pieces of information that I'd like to inject. Specifically: the AWS Request ID, CloudFront (or API Gateway) headers/trace IDs, and GitHub event IDs.

I found this issue that proposes something like:

const logger = pino.child({
      awsRequestId: context.awsRequestId,
})

But I can't figure out where to overwrite (or modify) the pino logger that Probot has already created.

Any ideas on where we could inject this additional info to make Lambda logs more useful?

Undefined event name in webhook handler

Just started using probot and while debugging noticed this:

03:01:34.721Z DEBUG probot: Webhook received
event: {
  "event": "undefined.synchronize",
  "installation": 101010,
  "repository": "owner/repo"
}

Traced it to
https://github.com/probot/serverless-lambda/blob/ee2e66125b930552d647e12676ef98b19fe10688/index.js#L45

Github might have changed the headers sent because at some point my bot was working:

X-Github-Event: pull_request

Current header has a slight spelling difference.

EDIT: GitHub seems to have fixed the header issue in their request but making this more robust would still be a good idea.

Make `GET /probot` template more flexible

As is, the behavior of the GET /probot HTML template is brittle and non-flexible:

// views/probot.js
const { name, version } = require(`${process.cwd()}/package`);

module.exports.template = `
  ... 
`

// index.js
const { template } = require("./views/probot");
...

// `template` is rendered on `GET /probot`
  1. It relies on the presence of a package module in process.cwd() at import time. This reliance seems unnecessary, and is also undocumented in the README.

  2. This require statement is not compatible with webpack, which cannot handle a dynamic import like this.

Thoughts on updating this behavior to be configurable, or swapping the require for a safer file read?

Unable to comment on PR

I'm trying to run the following probot using AWS Lambda that's getting events from a GHE instance.

  1. I used the example project and update the app.js to use the bot code.
  2. I also updated https://github.com/renovatebot/renovate-approve-bot/blob/80e0b5e0ea1d0b0b48862de39b813dce6cfd3d57/index.js#L47 to be return context.octokit.pulls.createReview(params); instead.

When the lambda triggers I am getting the following error

START RequestId: e62820aa-733b-4ef4-b750-c82ca20074fc Version: $LATEST
INFO (probot): App is loaded
INFO (event): Received PR open event
id: "d7c7fd70-100d-11ec-8fdd-a88238aa5068"
INFO (event): Approving new PR
id: "d7c7fd70-100d-11ec-8fdd-a88238aa5068"
ERROR (HttpError): Your private key (a .pem file or PRIVATE_KEY environment variable) or APP_ID is incorrect. Go to https://github.com/settings/apps/YOUR_APP, verify that APP_ID is set correctly, and generate a new PEM file if necessary.
HttpError: A JSON web token could not be decoded
at /var/task/src/node_modules/@octokit/request/dist-node/index.js:86:21
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async getInstallationAuthentication (/var/task/src/node_modules/@octokit/auth-app/dist-node/index.js:280:7)
at async hook (/var/task/src/node_modules/@octokit/auth-app/dist-node/index.js:449:7)
at async Job.doExecute (/var/task/src/node_modules/bottleneck/light.js:405:18) ```

I've set the following environment variables for the lambda

APP_ID
PRIVATE_KEY = (the value is from cat ghe_app_privateKey.pem)
WEBHOOK_SECRET
NODE_ENV
LOG_LEVEL

Running all this in nodejs12.x

async start

I've spend a few hours on this, and hoping there's an easy answer that I'm just missing somehow. Is there a way to wait to start listening for webhook events until some async things have happened, such as getting secrets from paramstore and setting them as envs?

dependency on probot is pinned to 7.x.x

package.json has probot dependency as "^7.5.1", whereas the latest probot is 9.0.2
is this intentional, or the plugin will work fine with 9.x.x and dependency just needs to be updated?

Cannot convert undefined or null to object

I am now seeing the following issue in CloudWatch in AWS and no changes have been made on the Lambda side nor the GitHub side.

Andy ideas?

{
    "errorMessage": "Cannot convert undefined or null to object",
    "errorType": "TypeError",
    "stackTrace": [
        "Function.keys (<anonymous>)",
        "lowerCaseKeys (/var/task/node_modules/@probot/serverless-lambda/index.js:25:10)",
        "/var/task/node_modules/@probot/serverless-lambda/index.js:49:21"
    ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.